You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2018/06/14 21:21:10 UTC

[ambari] branch branch-feature-AMBARI-14714 updated: [AMBARI-24106] - Upgrade History Model Changes (#1542)

This is an automated email from the ASF dual-hosted git repository.

jonathanhurley pushed a commit to branch branch-feature-AMBARI-14714
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/branch-feature-AMBARI-14714 by this push:
     new a5f2ea4  [AMBARI-24106] - Upgrade History Model Changes (#1542)
a5f2ea4 is described below

commit a5f2ea4905b959d0a581dfeb7020be2e2619503f
Author: Jonathan Hurley <jo...@apache.org>
AuthorDate: Thu Jun 14 17:20:56 2018 -0400

    [AMBARI-24106] - Upgrade History Model Changes (#1542)
---
 .../apache/ambari/annotations/Experimental.java    |   2 +-
 .../server/agent/stomp/HostLevelParamsHolder.java  |   5 +-
 .../ambari/server/agent/stomp/MetadataHolder.java  |   4 +-
 .../ambari/server/agent/stomp/TopologyHolder.java  |   4 +-
 .../event/request/AddUpgradeRequestAuditEvent.java |  12 +-
 .../request/eventcreator/UpgradeEventCreator.java  |   2 +-
 .../server/checks/AbstractCheckDescriptor.java     |  47 +-
 .../server/checks/PreviousUpgradeCompleted.java    |   7 +-
 .../checks/RequiredServicesInRepositoryCheck.java  |  60 --
 .../apache/ambari/server/checks/UpgradeCheck.java  |  11 -
 .../internal/PreUpgradeCheckResourceProvider.java  |  10 +-
 .../internal/UpgradeResourceProvider.java          | 277 +++-----
 .../apache/ambari/server/events/AmbariEvent.java   |   4 +-
 ...ent.java => ServiceGroupMpackChangedEvent.java} |   6 +-
 .../ambari/server/events/UpgradeUpdateEvent.java   |  12 -
 .../ambari/server/orm/entities/MpackEntity.java    |  18 +-
 .../orm/entities/RepositoryVersionEntity.java      |   8 -
 .../server/orm/entities/ServiceGroupEntity.java    |  13 +
 .../ambari/server/orm/entities/UpgradeEntity.java  | 143 ++--
 .../server/orm/entities/UpgradeHistoryEntity.java  | 132 ++--
 .../server/serveraction/ServerActionExecutor.java  |  28 +-
 .../serveraction/upgrades/ConfigureAction.java     |  19 +-
 .../upgrades/CreateAndConfigureAction.java         |  19 +-
 .../upgrades/FinalizeUpgradeAction.java            | 197 +++---
 .../serveraction/upgrades/FixNotebookStorage.java  |  96 ---
 .../upgrades/PreconfigureKerberosAction.java       |  15 +-
 .../upgrades/UpdateDesiredMpackAction.java         |  51 ++
 .../upgrades/UpdateDesiredRepositoryAction.java    | 156 ----
 .../upgrades/UpgradeUserKerberosDescriptor.java    |   7 +-
 .../ambari/server/stack/MasterHostResolver.java    |  23 +-
 .../org/apache/ambari/server/state/Module.java     |  35 +-
 .../ambari/server/state/ModuleComponent.java       |  71 +-
 .../java/org/apache/ambari/server/state/Mpack.java | 307 +++++++-
 .../apache/ambari/server/state/RepositoryType.java |  93 ---
 .../ambari/server/state/ServiceGroupImpl.java      |  43 ++
 .../apache/ambari/server/state/UpgradeContext.java | 787 +++++++++------------
 .../apache/ambari/server/state/UpgradeHelper.java  | 460 ++++++------
 .../ambari/server/state/repository/Release.java    |   7 -
 .../state/services/RetryUpgradeActionService.java  |  10 +-
 .../state/stack/upgrade/ClusterGrouping.java       |  16 +-
 .../state/stack/upgrade/ColocatedGrouping.java     |   8 +-
 .../server/state/stack/upgrade/Grouping.java       |   8 +-
 .../state/stack/upgrade/HostOrderGrouping.java     |  41 +-
 .../state/stack/upgrade/ServiceCheckGrouping.java  |   5 +-
 .../state/stack/upgrade/StageWrapperBuilder.java   |  12 +-
 .../ambari/server/state/stack/upgrade/Task.java    |   7 -
 .../server/state/stack/upgrade/UpgradeScope.java   |  51 --
 .../src/main/resources/Ambari-DDL-Derby-CREATE.sql |   6 +-
 .../src/main/resources/Ambari-DDL-MySQL-CREATE.sql |   6 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql    |   6 +-
 .../main/resources/Ambari-DDL-Postgres-CREATE.sql  |   6 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql    |   6 +-
 .../main/resources/Ambari-DDL-SQLServer-CREATE.sql |   6 +-
 ambari-server/src/main/resources/upgrade-pack.xsd  |  11 -
 .../request/creator/UpgradeEventCreatorTest.java   |   4 +-
 .../RequiredServicesInRepositoryCheckTest.java     | 106 ---
 .../PreUpgradeCheckResourceProviderTest.java       |   2 +-
 .../UpgradeSummaryResourceProviderTest.java        |   2 -
 .../upgrades/ComponentVersionCheckActionTest.java  |  20 +-
 .../upgrades/CreateAndConfigureActionTest.java     |  18 +-
 60 files changed, 1525 insertions(+), 2023 deletions(-)

diff --git a/ambari-server/src/main/java/org/apache/ambari/annotations/Experimental.java b/ambari-server/src/main/java/org/apache/ambari/annotations/Experimental.java
index 74f76c8..36d25e6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/annotations/Experimental.java
+++ b/ambari-server/src/main/java/org/apache/ambari/annotations/Experimental.java
@@ -30,7 +30,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.SOURCE)
 @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR,
     ElementType.ANNOTATION_TYPE, ElementType.PACKAGE, ElementType.FIELD,
-    ElementType.LOCAL_VARIABLE })
+    ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
 public @interface Experimental {
 
   /**
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
index b2c1b22..b6a20ad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
@@ -24,8 +24,8 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.RecoveryConfigHelper;
 import org.apache.ambari.server.agent.stomp.dto.HostLevelParamsCluster;
 import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.events.ClusterComponentsRepoChangedEvent;
 import org.apache.ambari.server.events.HostLevelParamsUpdateEvent;
+import org.apache.ambari.server.events.ServiceGroupMpackChangedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -70,6 +70,7 @@ public class HostLevelParamsHolder extends AgentHostDataHolder<HostLevelParamsUp
     return hostLevelParamsUpdateEvent;
   }
 
+  @Override
   protected boolean handleUpdate(HostLevelParamsUpdateEvent update) throws AmbariException {
     //TODO implement update host level params process
     setData(update, update.getHostId());
@@ -82,7 +83,7 @@ public class HostLevelParamsHolder extends AgentHostDataHolder<HostLevelParamsUp
   }
 
   @Subscribe
-  public void onClusterComponentsRepoUpdate(ClusterComponentsRepoChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
+  public void onUpgradeDesiredMpackChange(ServiceGroupMpackChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
     Long clusterId = clusterComponentsRepoChangedEvent.getClusterId();
 
     Cluster cluster = clusters.getCluster(clusterId);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
index 7cd6399..437ee9f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
@@ -21,9 +21,9 @@ import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.stomp.dto.MetadataCluster;
-import org.apache.ambari.server.events.ClusterComponentsRepoChangedEvent;
 import org.apache.ambari.server.events.ClusterConfigChangedEvent;
 import org.apache.ambari.server.events.MetadataUpdateEvent;
+import org.apache.ambari.server.events.ServiceGroupMpackChangedEvent;
 import org.apache.ambari.server.events.ServiceInstalledEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.metadata.ClusterMetadataGenerator;
@@ -96,7 +96,7 @@ public class MetadataHolder extends AgentClusterDataHolder<MetadataUpdateEvent>
   }
 
   @Subscribe
-  public void onClusterComponentsRepoUpdate(ClusterComponentsRepoChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
+  public void onUpgradeDesiredMpackChange(ServiceGroupMpackChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
     Cluster cluster = m_clusters.get().getCluster(clusterComponentsRepoChangedEvent.getClusterId());
     updateData(metadataGenerator.getClusterMetadataOnRepoUpdate(cluster));
   }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
index e5f9339..1d0ec44 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
@@ -30,7 +30,7 @@ import org.apache.ambari.server.agent.stomp.dto.TopologyCluster;
 import org.apache.ambari.server.agent.stomp.dto.TopologyComponent;
 import org.apache.ambari.server.agent.stomp.dto.TopologyHost;
 import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
-import org.apache.ambari.server.events.ClusterComponentsRepoChangedEvent;
+import org.apache.ambari.server.events.ServiceGroupMpackChangedEvent;
 import org.apache.ambari.server.events.TopologyAgentUpdateEvent;
 import org.apache.ambari.server.events.TopologyUpdateEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
@@ -192,7 +192,7 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
   }
 
   @Subscribe
-  public void onClusterComponentsRepoUpdate(ClusterComponentsRepoChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
+  public void onUpgradeDesiredMpackChange(ServiceGroupMpackChangedEvent clusterComponentsRepoChangedEvent) throws AmbariException {
     Long clusterId = clusterComponentsRepoChangedEvent.getClusterId();
 
     TopologyCluster topologyCluster = new TopologyCluster();
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/request/AddUpgradeRequestAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/request/AddUpgradeRequestAuditEvent.java
index 215c232..c971ac9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/request/AddUpgradeRequestAuditEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/request/AddUpgradeRequestAuditEvent.java
@@ -31,9 +31,9 @@ public class AddUpgradeRequestAuditEvent extends RequestAuditEvent {
   public static class AddUpgradeRequestAuditEventBuilder extends RequestAuditEventBuilder<AddUpgradeRequestAuditEvent, AddUpgradeRequestAuditEventBuilder> {
 
     /**
-     * Repository version
+     * Upgrade plan ID.
      */
-    private String repositoryVersionId;
+    private String upgradePlanId;
 
     /**
      * Upgrade type (rolling, non-rolling)
@@ -65,8 +65,8 @@ public class AddUpgradeRequestAuditEvent extends RequestAuditEvent {
     protected void buildAuditMessage(StringBuilder builder) {
       super.buildAuditMessage(builder);
 
-      builder.append(", Repository version ID(")
-        .append(repositoryVersionId)
+      builder.append(", Upgrade Plan ID(")
+        .append(upgradePlanId)
         .append("), Upgrade type(")
         .append(upgradeType)
         .append("), Cluster name(")
@@ -74,8 +74,8 @@ public class AddUpgradeRequestAuditEvent extends RequestAuditEvent {
         .append(")");
     }
 
-    public AddUpgradeRequestAuditEventBuilder withRepositoryVersionId(String repositoryVersionId) {
-      this.repositoryVersionId = repositoryVersionId;
+    public AddUpgradeRequestAuditEventBuilder withUpgradePlanId(String upgradePlanId) {
+      this.upgradePlanId = upgradePlanId;
       return this;
     }
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeEventCreator.java
index db4549f..3167ef8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeEventCreator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeEventCreator.java
@@ -83,7 +83,7 @@ public class UpgradeEventCreator implements RequestAuditEventCreator {
       .withResultStatus(result.getStatus())
       .withUrl(request.getURI())
       .withRemoteIp(request.getRemoteAddress())
-      .withRepositoryVersionId(RequestAuditEventCreatorHelper.getProperty(request, UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID))
+      .withUpgradePlanId(RequestAuditEventCreatorHelper.getProperty(request, UpgradeResourceProvider.UPGRADE_PLAN_ID))
       .withUpgradeType(RequestAuditEventCreatorHelper.getProperty(request, UpgradeResourceProvider.UPGRADE_TYPE))
       .withClusterName(RequestAuditEventCreatorHelper.getProperty(request, UpgradeResourceProvider.UPGRADE_CLUSTER_NAME))
       .build();
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
index d2c84ed..c48b5e0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
@@ -35,7 +35,6 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.DesiredConfig;
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrereqCheckType;
@@ -43,7 +42,6 @@ import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
-import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
 import org.codehaus.jackson.annotate.JsonProperty;
 
@@ -124,7 +122,7 @@ public abstract class AbstractCheckDescriptor {
    */
   public final boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
     List<CheckQualification> qualifications = Lists.newArrayList(
-        new ServiceQualification(), new OrchestrationQualification(getClass()));
+        new ServiceQualification());
 
     // add any others from the concrete check
     qualifications.addAll(getQualifications());
@@ -388,49 +386,6 @@ public abstract class AbstractCheckDescriptor {
   }
 
   /**
-   * The {@link OrchestrationQualification} class is used to determine if the
-   * check is required to run based on the {@link RepositoryType}.
-   */
-  final class OrchestrationQualification implements CheckQualification {
-
-    private final Class<? extends AbstractCheckDescriptor> m_checkClass;
-
-    /**
-     * Constructor.
-     *
-     * @param checkClass
-     *          the class of the check which is being considered for
-     *          applicability.
-     */
-    public OrchestrationQualification(Class<? extends AbstractCheckDescriptor> checkClass) {
-      m_checkClass = checkClass;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
-      RepositoryVersionEntity repositoryVersion = request.getTargetRepositoryVersion();
-      RepositoryType repositoryType = repositoryVersion.getType();
-
-      UpgradeCheck annotation = m_checkClass.getAnnotation(UpgradeCheck.class);
-      if (null == annotation) {
-        return true;
-      }
-
-      RepositoryType[] repositoryTypes = annotation.orchestration();
-
-      if (ArrayUtils.isEmpty(repositoryTypes)
-          || ArrayUtils.contains(repositoryTypes, repositoryType)) {
-        return true;
-      }
-
-      return false;
-    }
-  }
-
-  /**
    * Used to represent information about a service. This class is safe to use in
    * sorted & unique collections.
    */
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/PreviousUpgradeCompleted.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/PreviousUpgradeCompleted.java
index cab1ea4..286ffd7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/PreviousUpgradeCompleted.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/PreviousUpgradeCompleted.java
@@ -46,7 +46,7 @@ public class PreviousUpgradeCompleted extends AbstractCheckDescriptor {
   /**
    * The message displayed as part of this pre-upgrade check.
    */
-  public static final String ERROR_MESSAGE = "There is an existing {0} {1} {2} which has not completed. This {3} must be completed before a new upgrade or downgrade can begin.";
+  public static final String ERROR_MESSAGE = "There is an existing {0} with ID {1} which has not completed. This {2} must be completed before a new upgrade or downgrade can begin.";
 
   /**
    * Constructor.
@@ -65,10 +65,9 @@ public class PreviousUpgradeCompleted extends AbstractCheckDescriptor {
     if (null != upgradeInProgress) {
       Direction direction = upgradeInProgress.getDirection();
       String directionText = direction.getText(false);
-      String prepositionText = direction.getPreposition();
 
-      errorMessage = MessageFormat.format(ERROR_MESSAGE, directionText, prepositionText,
-          upgradeInProgress.getRepositoryVersion().getVersion(), directionText);
+      errorMessage = MessageFormat.format(ERROR_MESSAGE, directionText, upgradeInProgress.getId(),
+          directionText);
     }
 
     if (null != errorMessage) {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheck.java
deleted file mode 100644
index 0125043..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheck.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.checks;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.controller.PrereqCheckRequest;
-import org.apache.ambari.server.state.RepositoryType;
-import org.apache.ambari.server.state.stack.PrereqCheckStatus;
-import org.apache.ambari.server.state.stack.PrerequisiteCheck;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
-
-import com.google.inject.Singleton;
-
-/**
- * The {@link RequiredServicesInRepositoryCheck} is used to ensure that if there
- * are any services which require other services to also be included in the
- * upgrade that they are included in the repository.
- * <p/>
- * This check is to prevent problems which can be caused by trying to patch
- * upgrade services which have known depdenencies on other services because of
- * things like hard coded versions.
- */
-@Singleton
-@UpgradeCheck(
-    group = UpgradeCheckGroup.REPOSITORY_VERSION,
-    order = 1.0f,
-    required = { UpgradeType.ROLLING, UpgradeType.EXPRESS, UpgradeType.HOST_ORDERED },
-    orchestration = { RepositoryType.PATCH, RepositoryType.MAINT, RepositoryType.SERVICE })
-public class RequiredServicesInRepositoryCheck extends AbstractCheckDescriptor {
-
-  /**
-   * Constructor.
-   */
-  public RequiredServicesInRepositoryCheck() {
-    super(CheckDescription.VALID_SERVICES_INCLUDED_IN_REPOSITORY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
-    prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
-  }
-}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
index 4e03f47..58ef4ba 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
@@ -23,7 +23,6 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 import com.google.inject.ScopeAnnotation;
@@ -70,14 +69,4 @@ public @interface UpgradeCheck {
    *         defined in the upgrade pack or an empty array for none.
    */
   UpgradeType[] required() default {};
-
-
-  /**
-   * The valid orchestration repository type that this check if valid for. By
-   * default, a check is valid for all orchestration types.
-   *
-   * @return the repository types that the check is valid for.
-   */
-  RepositoryType[] orchestration() default { RepositoryType.STANDARD, RepositoryType.PATCH,
-      RepositoryType.MAINT, RepositoryType.SERVICE };
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
index ae378df..e5da5d7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
@@ -79,7 +79,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
   public static final String UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID          = PropertyHelper.getPropertyId("UpgradeChecks", "check_type");
   public static final String UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID        = PropertyHelper.getPropertyId("UpgradeChecks", "cluster_name");
   public static final String UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID        = PropertyHelper.getPropertyId("UpgradeChecks", "upgrade_type");
-  public static final String UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID = PropertyHelper.getPropertyId("UpgradeChecks", "repository_version_id");
+  public static final String UPGRADE_CHECK_UPGRADE_PLAN_ID = PropertyHelper.getPropertyId("UpgradeChecks", "upgrade_plan_id");
   public static final String UPGRADE_CHECK_TARGET_REPOSITORY_VERSION       = PropertyHelper.getPropertyId("UpgradeChecks", "repository_version");
 
   /**
@@ -117,7 +117,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
       UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID,
       UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID,
       UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID,
-      UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID,
+      UPGRADE_CHECK_UPGRADE_PLAN_ID,
       UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID);
 
 
@@ -167,12 +167,12 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
       }
 
       String repositoryVersionId = (String) propertyMap.get(
-          UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID);
+          UPGRADE_CHECK_UPGRADE_PLAN_ID);
 
       if (StringUtils.isBlank(repositoryVersionId)) {
         throw new SystemException(
             String.format("%s is a required property when executing upgrade checks",
-                UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID));
+                UPGRADE_CHECK_UPGRADE_PLAN_ID));
       }
 
       final PrereqCheckRequest upgradeCheckRequest = new PrereqCheckRequest(clusterName,
@@ -241,7 +241,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
         setResourceProperty(resource, UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID, prerequisiteCheck.getClusterName(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID, upgradeType, requestedIds);
 
-        setResourceProperty(resource, UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID, repositoryVersion.getId(), requestedIds);
+        setResourceProperty(resource, UPGRADE_CHECK_UPGRADE_PLAN_ID, repositoryVersion.getId(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_TARGET_REPOSITORY_VERSION, repositoryVersion.getVersion(), requestedIds);
 
         resources.add(resource);
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 c49571d..f01547e 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
@@ -17,9 +17,6 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
-
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -70,9 +67,8 @@ import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
 import org.apache.ambari.server.orm.dao.RequestDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.MpackEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
-import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
@@ -84,11 +80,7 @@ import org.apache.ambari.server.security.authorization.RoleAuthorization;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
-import org.apache.ambari.server.state.Service;
-import org.apache.ambari.server.state.ServiceComponent;
-import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeContextFactory;
 import org.apache.ambari.server.state.UpgradeHelper;
@@ -104,7 +96,6 @@ import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
 import org.apache.ambari.server.state.stack.upgrade.Task;
 import org.apache.ambari.server.state.stack.upgrade.TaskWrapper;
 import org.apache.ambari.server.state.stack.upgrade.UpdateStackGrouping;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeScope;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent;
 import org.apache.ambari.server.utils.StageUtils;
@@ -132,12 +123,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
   static final String DUMMY_SERVICE_GROUP = "CORE"; // FIXME need a service group name, since null or "" is not allowed
 
   public static final String UPGRADE_CLUSTER_NAME = "Upgrade/cluster_name";
-  public static final String UPGRADE_REPO_VERSION_ID = "Upgrade/repository_version_id";
+  public static final String UPGRADE_PLAN_ID = "Upgrade/upgrade_plan_id";
   public static final String UPGRADE_TYPE = "Upgrade/upgrade_type";
   public static final String UPGRADE_PACK = "Upgrade/pack";
   public static final String UPGRADE_ID = "Upgrade/upgrade_id";
   public static final String UPGRADE_REQUEST_ID = "Upgrade/request_id";
-  public static final String UPGRADE_ASSOCIATED_VERSION = "Upgrade/associated_version";
+  public static final String UPGRADE_SUMMARY = "Upgrade/summary";
   public static final String UPGRADE_VERSIONS = "Upgrade/versions";
   public static final String UPGRADE_DIRECTION = "Upgrade/direction";
   public static final String UPGRADE_DOWNGRADE_ALLOWED = "Upgrade/downgrade_allowed";
@@ -271,12 +262,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
   static {
     // properties
     PROPERTY_IDS.add(UPGRADE_CLUSTER_NAME);
-    PROPERTY_IDS.add(UPGRADE_REPO_VERSION_ID);
+    PROPERTY_IDS.add(UPGRADE_PLAN_ID);
     PROPERTY_IDS.add(UPGRADE_TYPE);
     PROPERTY_IDS.add(UPGRADE_PACK);
     PROPERTY_IDS.add(UPGRADE_ID);
     PROPERTY_IDS.add(UPGRADE_REQUEST_ID);
-    PROPERTY_IDS.add(UPGRADE_ASSOCIATED_VERSION);
+    PROPERTY_IDS.add(UPGRADE_SUMMARY);
     PROPERTY_IDS.add(UPGRADE_VERSIONS);
     PROPERTY_IDS.add(UPGRADE_DIRECTION);
     PROPERTY_IDS.add(UPGRADE_DOWNGRADE_ALLOWED);
@@ -414,7 +405,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       }
 
       for (UpgradeEntity entity : upgrades) {
-        Resource r = toResource(entity, clusterName, requestPropertyIds);
+        Resource r = toResource(entity, cluster, requestPropertyIds);
         results.add(r);
 
         RequestEntity rentity = s_requestDAO.findByPK(entity.getRequestId());
@@ -628,11 +619,11 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     return PK_PROPERTY_IDS;
   }
 
-  private Resource toResource(UpgradeEntity entity, String clusterName, Set<String> requestedIds) {
+  private Resource toResource(UpgradeEntity entity, Cluster cluster, Set<String> requestedIds) {
     ResourceImpl resource = new ResourceImpl(Resource.Type.Upgrade);
 
     setResourceProperty(resource, UPGRADE_ID, entity.getId(), requestedIds);
-    setResourceProperty(resource, UPGRADE_CLUSTER_NAME, clusterName, requestedIds);
+    setResourceProperty(resource, UPGRADE_CLUSTER_NAME, cluster.getClusterName(), requestedIds);
     setResourceProperty(resource, UPGRADE_TYPE, entity.getUpgradeType(), requestedIds);
     setResourceProperty(resource, UPGRADE_PACK, entity.getUpgradePackage(), requestedIds);
     setResourceProperty(resource, UPGRADE_REQUEST_ID, entity.getRequestId(), requestedIds);
@@ -643,21 +634,22 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     setResourceProperty(resource, UPGRADE_SKIP_SC_FAILURES, entity.isServiceCheckFailureAutoSkipped(), requestedIds);
 
     // set the assocaited to/from version (to/from is dictated by direction)
-    RepositoryVersionEntity repositoryVersion = entity.getRepositoryVersion();
-    setResourceProperty(resource, UPGRADE_ASSOCIATED_VERSION, repositoryVersion.getVersion(), requestedIds);
+    if (requestedIds.contains(UPGRADE_SUMMARY)) {
+      UpgradeContext context = s_upgradeContextFactory.create(cluster, entity);
+      setResourceProperty(resource, UPGRADE_SUMMARY, context.getUpgradeSummary(), requestedIds);
+    }
 
     // now set the target verison for all services in the upgrade
     Map<String, RepositoryVersions> repositoryVersions = new HashMap<>();
     for( UpgradeHistoryEntity history : entity.getHistory() ){
-      RepositoryVersions serviceVersions = repositoryVersions.get(history.getServiceName());
+      String serviceGroupName = history.getServiceGroupEntity().getServiceGroupName();
+      RepositoryVersions serviceVersions = repositoryVersions.get(serviceGroupName);
       if (null != serviceVersions) {
         continue;
       }
 
-      serviceVersions = new RepositoryVersions(history.getFromReposistoryVersion(),
-          history.getTargetRepositoryVersion());
-
-      repositoryVersions.put(history.getServiceName(), serviceVersions);
+      serviceVersions = new RepositoryVersions(history.getSourceMpackEntity(), history.getTargetMpackEntity());
+      repositoryVersions.put(serviceGroupName, serviceVersions);
     }
 
     setResourceProperty(resource, UPGRADE_VERSIONS, repositoryVersions, requestedIds);
@@ -753,7 +745,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     RequestStageContainer req = createRequest(upgradeContext);
 
     UpgradeEntity upgrade = new UpgradeEntity();
-    upgrade.setRepositoryVersion(upgradeContext.getRepositoryVersion());
     upgrade.setClusterId(cluster.getClusterId());
     upgrade.setDirection(direction);
     upgrade.setUpgradePackage(pack.getName());
@@ -761,34 +752,21 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     upgrade.setAutoSkipComponentFailures(upgradeContext.isComponentFailureAutoSkipped());
     upgrade.setAutoSkipServiceCheckFailures(upgradeContext.isServiceCheckFailureAutoSkipped());
     upgrade.setDowngradeAllowed(upgradeContext.isDowngradeAllowed());
-    upgrade.setOrchestration(upgradeContext.getOrchestrationType());
 
     // create to/from history for this upgrade - this should be done before any
     // possible changes to the desired version for components
     addComponentHistoryToUpgrade(cluster, upgrade, upgradeContext);
 
-    /*
-    During a Rolling Upgrade, change the desired Stack Id if jumping across
-    major stack versions (e.g., HDP 2.2 -> 2.3), and then set config changes
-    so they are applied on the newer stack.
-
-    During a {@link UpgradeType.NON_ROLLING} upgrade, the stack is applied during the middle of the upgrade (after
-    stopping all services), and the configs are applied immediately before starting the services.
-    The Upgrade Pack is responsible for calling {@link org.apache.ambari.server.serveraction.upgrades.UpdateDesiredRepositoryAction}
-    at the appropriate moment during the orchestration.
-    */
-    if (pack.getType() == UpgradeType.ROLLING || pack.getType() == UpgradeType.HOST_ORDERED) {
-      if (direction == Direction.UPGRADE) {
-        StackEntity targetStack = upgradeContext.getRepositoryVersion().getStack();
-        cluster.setDesiredStackVersion(
-            new StackId(targetStack.getStackName(), targetStack.getStackVersion()));
-      }
-      s_upgradeHelper.updateDesiredRepositoriesAndConfigs(upgradeContext);
-      s_upgradeHelper.publishDesiredRepositoriesUpdates(upgradeContext);
-      if (direction == Direction.DOWNGRADE) {
-        StackId targetStack = upgradeContext.getCluster().getCurrentStackVersion();
-        cluster.setDesiredStackVersion(targetStack);
+    // update configs and move mpack versions for some upgrade types
+    switch (pack.getType()) {
+      case ROLLING:
+      case HOST_ORDERED: {
+        s_upgradeHelper.updateDesiredMpacksAndConfigs(upgradeContext);
+        s_upgradeHelper.publishServiceGroupMpackChangeUpdate(upgradeContext);
+        break;
       }
+      default:
+        break;
     }
 
     // resolve or build a proper config upgrade pack - always start out with the config pack
@@ -803,8 +781,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       List<UpgradeItemEntity> itemEntities = new ArrayList<>();
 
       for (StageWrapper wrapper : group.items) {
-        RepositoryVersionEntity effectiveRepositoryVersion = upgradeContext.getRepositoryVersion();
-
         if (wrapper.getType() == StageWrapper.Type.SERVER_SIDE_ACTION) {
           // !!! each stage is guaranteed to be of one type. but because there
           // is a bug that prevents one stage with multiple tasks assigned for
@@ -823,7 +799,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
               itemEntity.setHosts(wrapper.getHostsJson());
 
               injectVariables(configHelper, cluster, itemEntity);
-              if (makeServerSideStage(group, upgradeContext, effectiveRepositoryVersion, req,
+              if (makeServerSideStage(group, upgradeContext, null, req,
                   itemEntity, (ServerSideActionTask) task, configUpgradePack)) {
                 itemEntities.add(itemEntity);
               }
@@ -839,7 +815,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           injectVariables(configHelper, cluster, itemEntity);
 
           // upgrade items match a stage
-          createStage(group, upgradeContext, effectiveRepositoryVersion, req, itemEntity, wrapper);
+          createStage(group, upgradeContext, null, req, itemEntity, wrapper);
         }
       }
 
@@ -915,10 +891,10 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
         actionManager.getNextRequestId(), null, s_requestFactory.get(), actionManager);
 
     Direction direction = upgradeContext.getDirection();
-    RepositoryVersionEntity repositoryVersion = upgradeContext.getRepositoryVersion();
+    String requestContext = String.format("%s %s: \n%s", direction.getText(true),
+        direction.getPreposition(), upgradeContext.getServiceGroupDisplayableSummary());
 
-    requestStages.setRequestContext(String.format("%s %s %s", direction.getVerb(true),
-        direction.getPreposition(), repositoryVersion.getVersion()));
+    requestStages.setRequestContext(requestContext);
 
     Cluster cluster = upgradeContext.getCluster();
     Map<String, Set<String>> clusterHostInfo = StageUtils.getClusterHostInfo(cluster);
@@ -928,10 +904,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     return requestStages;
   }
 
-  private void createStage(UpgradeGroupHolder group, UpgradeContext context,
-      RepositoryVersionEntity effectiveRepositoryVersion,
+  private void createStage(UpgradeGroupHolder group, UpgradeContext context, StackId stackId,
       RequestStageContainer request, UpgradeItemEntity entity, StageWrapper wrapper)
-          throws AmbariException {
+      throws AmbariException {
 
     boolean skippable = group.skippable;
     boolean supportsAutoSkipOnFailure = group.supportsAutoSkipOnFailure;
@@ -942,15 +917,15 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       case START:
       case STOP:
       case RESTART:
-        makeCommandStage(context, request, effectiveRepositoryVersion, entity, wrapper, skippable,
+        makeCommandStage(context, request, stackId, entity, wrapper, skippable,
             supportsAutoSkipOnFailure, allowRetry);
         break;
       case UPGRADE_TASKS:
-        makeActionStage(context, request, effectiveRepositoryVersion, entity, wrapper, skippable,
+        makeActionStage(context, request, stackId, entity, wrapper, skippable,
             supportsAutoSkipOnFailure, allowRetry);
         break;
       case SERVICE_CHECK:
-        makeServiceCheckStage(context, request, effectiveRepositoryVersion, entity, wrapper,
+        makeServiceCheckStage(context, request, stackId, entity, wrapper,
             skippable, supportsAutoSkipOnFailure, allowRetry);
         break;
       default:
@@ -974,37 +949,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
   }
 
   /**
-   * Adds the hooks and service folders based on the effective stack ID and the
-   * name of the service from the wrapper.
-   *
-   * @param wrapper
-   *          the stage wrapper to use when detemrining the service name.
-   * @param effectiveStackId
-   *          the stack ID to use when getting the hooks and service folders.
-   * @param commandParams
-   *          the params to update with the new values
-   * @throws AmbariException
-   */
-  private void applyRepositoryAssociatedParameters(StageWrapper wrapper, StackId effectiveStackId,
-      Map<String, String> commandParams) throws AmbariException {
-    if (CollectionUtils.isNotEmpty(wrapper.getTasks())
-        && wrapper.getTasks().get(0).getService() != null) {
-
-      AmbariMetaInfo ambariMetaInfo = s_metaProvider.get();
-
-      StackInfo stackInfo = ambariMetaInfo.getStack(effectiveStackId.getStackName(),
-          effectiveStackId.getStackVersion());
-
-      String serviceName = wrapper.getTasks().get(0).getService();
-      ServiceInfo serviceInfo = ambariMetaInfo.getService(effectiveStackId.getStackName(),
-          effectiveStackId.getStackVersion(), serviceName);
-
-      commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder());
-      commandParams.put(HOOKS_FOLDER, s_configuration.getProperty(Configuration.HOOKS_FOLDER));
-    }
-  }
-
-  /**
    * Creates an action stage using the {@link #EXECUTE_TASK_ROLE} custom action
    * to execute some Python command.
    *
@@ -1012,9 +956,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    *          the upgrade context.
    * @param request
    *          the request object to add the stage to.
-   * @param effectiveRepositoryVersion
-   *          the stack/version to use when generating content for the command.
-   *          On some upgrade types, this may change during the course of the
+   * @param stackId
+   *          ID the stack to use when generating content for the command. On
+   *          some upgrade types, this may change during the course of the
    *          upgrade orchestration. An express upgrade changes this after
    *          stopping all services.
    * @param entity
@@ -1031,7 +975,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    * @throws AmbariException
    */
   private void makeActionStage(UpgradeContext context, RequestStageContainer request,
-      RepositoryVersionEntity effectiveRepositoryVersion, UpgradeItemEntity entity,
+      StackId stackId, UpgradeItemEntity entity,
       StageWrapper wrapper, boolean skippable, boolean supportsAutoSkipOnFailure,
       boolean allowRetry) throws AmbariException {
 
@@ -1058,26 +1002,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     Map<String, String> params = getNewParameterMap(request, context);
     params.put(UpgradeContext.COMMAND_PARAM_TASKS, entity.getTasks());
 
-    // !!! when not scoped to a component (generic execution task)
-    if (context.isScoped(UpgradeScope.COMPLETE) && null == componentName) {
-      if (context.getDirection().isUpgrade()) {
-        params.put(KeyNames.VERSION, context.getRepositoryVersion().getVersion());
-      } else {
-        // !!! in a full downgrade, the target version should be any of the history versions
-        UpgradeEntity lastUpgrade = s_upgradeDAO.findLastUpgradeForCluster(
-            cluster.getClusterId(), Direction.UPGRADE);
-
-        @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES,
-            comment = "Shouldn't be getting the overall downgrade-to version.")
-        UpgradeHistoryEntity lastHistory = lastUpgrade.getHistory().iterator().next();
-        params.put(KeyNames.VERSION, lastHistory.getFromReposistoryVersion().getVersion());
-      }
-    }
-
     // Apply additional parameters to the command that come from the stage.
     applyAdditionalParameters(wrapper, params);
 
-
     // add each host to this stage
     //TODO pass service group name once upgrade is fixed
     RequestResourceFilter filter = new RequestResourceFilter(DUMMY_SERVICE_GROUP, serviceName, componentName,
@@ -1094,7 +1021,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped());
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster, effectiveRepositoryVersion.getStackId(), null);
+        cluster, stackId, null);
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getCommandParamsForStage(),
@@ -1125,16 +1052,25 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
   /**
    * Used to create a stage for restart, start, or stop.
-   * @param context Upgrade Context
-   * @param request Container for stage
-   * @param entity Upgrade Item
-   * @param wrapper Stage
-   * @param skippable Whether the item can be skipped
-   * @param allowRetry Whether the item is allowed to be retried
+   *
+   * @param context
+   *          Upgrade Context
+   * @param request
+   *          Container for stage
+   * @param stackId
+   *          stack ID
+   * @param entity
+   *          Upgrade Item
+   * @param wrapper
+   *          Stage
+   * @param skippable
+   *          Whether the item can be skipped
+   * @param allowRetry
+   *          Whether the item is allowed to be retried
    * @throws AmbariException
    */
   private void makeCommandStage(UpgradeContext context, RequestStageContainer request,
-      RepositoryVersionEntity effectiveRepositoryVersion, UpgradeItemEntity entity,
+      StackId stackId, UpgradeItemEntity entity,
       StageWrapper wrapper, boolean skippable, boolean supportsAutoSkipOnFailure,
       boolean allowRetry) throws AmbariException {
 
@@ -1177,7 +1113,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setMaintenanceModeHostExcluded(true);
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster, effectiveRepositoryVersion.getStackId(), null);
+        cluster, stackId, null);
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getCommandParamsForStage(),
@@ -1209,7 +1145,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
   }
 
   private void makeServiceCheckStage(UpgradeContext context, RequestStageContainer request,
-      RepositoryVersionEntity effectiveRepositoryVersion, UpgradeItemEntity entity,
+      StackId stackId, UpgradeItemEntity entity,
       StageWrapper wrapper, boolean skippable, boolean supportsAutoSkipOnFailure,
       boolean allowRetry) throws AmbariException {
 
@@ -1239,7 +1175,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setMaintenanceModeHostExcluded(true);
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster, effectiveRepositoryVersion.getStackId(), null);
+        cluster, stackId, null);
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getCommandParamsForStage(),
@@ -1274,9 +1210,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    * @throws AmbariException
    */
   private boolean makeServerSideStage(UpgradeGroupHolder group, UpgradeContext context,
-      RepositoryVersionEntity effectiveRepositoryVersion, RequestStageContainer request,
-      UpgradeItemEntity entity, ServerSideActionTask task, ConfigUpgradePack configUpgradePack)
-      throws AmbariException {
+      StackId stackId, RequestStageContainer request, UpgradeItemEntity entity,
+      ServerSideActionTask task, ConfigUpgradePack configUpgradePack) throws AmbariException {
 
     Cluster cluster = context.getCluster();
     UpgradePack upgradePack = context.getUpgradePack();
@@ -1330,7 +1265,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
         // !!! would prefer to do this in the sequence generator, but there's too many
         // places to miss
-        if (context.getOrchestrationType().isRevertable() && !ct.supportsPatch) {
+        if (context.isRevertable() && !ct.supportsPatch) {
           process = false;
         }
 
@@ -1365,7 +1300,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
         // !!! would prefer to do this in the sequence generator, but there's too many
         // places to miss
-        if (context.getOrchestrationType().isRevertable() && !ct.supportsPatch) {
+        if (context.isRevertable() && !ct.supportsPatch) {
           process = false;
         }
 
@@ -1415,7 +1350,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setMaintenanceModeHostExcluded(true);
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster, context.getRepositoryVersion().getStackId(), null);
+        cluster, stackId, null);
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), stageText, jsons.getCommandParamsForStage(),
@@ -1574,37 +1509,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    * @param upgradeContext
    *          the upgrade context for this upgrade (not {@code null}).
    */
+  @Experimental(feature = ExperimentalFeature.MPACK_UPGRADES, comment = "Need to implement")
   private void addComponentHistoryToUpgrade(Cluster cluster, UpgradeEntity upgrade,
       UpgradeContext upgradeContext) throws AmbariException {
-    Set<String> services = upgradeContext.getSupportedServices();
-    for (String serviceName : services) {
-      Service service = cluster.getService(serviceName);
-      Map<String, ServiceComponent> componentMap = service.getServiceComponents();
-      for (ServiceComponent component : componentMap.values()) {
-        UpgradeHistoryEntity history = new UpgradeHistoryEntity();
-        history.setUpgrade(upgrade);
-        history.setServiceName(serviceName);
-        history.setComponentName(component.getName());
-
-        // depending on whether this is an upgrade or a downgrade, the history
-        // will be different
-        if (upgradeContext.getDirection() == Direction.UPGRADE || upgradeContext.isPatchRevert()) {
-          history.setFromRepositoryVersion(null);
-          history.setTargetRepositoryVersion(upgradeContext.getRepositoryVersion());
-        } else {
-          // the target version on a downgrade is the original version that the
-          // service was on in the failed upgrade
-          RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
-              serviceName);
-
-          history.setFromRepositoryVersion(upgradeContext.getRepositoryVersion());
-          history.setTargetRepositoryVersion(targetRepositoryVersion);
-        }
-
-        // add the history
-        upgrade.addHistory(history);
-      }
-    }
   }
 
   /**
@@ -1639,13 +1546,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
      */
     public static ConfigUpgradePack build(UpgradeContext cx) {
       final UpgradePack upgradePack = cx.getUpgradePack();
-      final StackId stackId;
-
-      if (cx.getDirection() == Direction.UPGRADE) {
-        stackId = cx.getStackIdFromVersions(cx.getSourceVersions());
-      } else {
-        stackId = cx.getStackIdFromVersions(cx.getTargetVersions());
-      }
+      final StackId stackId = null;
 
       ConfigUpgradePack configUpgradePack = s_metaProvider.get().getConfigUpgradePack(
         stackId.getStackName(), stackId.getStackVersion());
@@ -1656,30 +1557,46 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
   /**
    * The {@link RepositoryVersions} class is used to represent to/from versions
-   * of a service during an upgrade or downgrade.
+   * of a service group during an upgrade or downgrade.
    */
   final static class RepositoryVersions {
-    @JsonProperty("from_repository_id")
-    final long fromRepositoryId;
+    @JsonProperty("source_mpack_id")
+    final long sourceMpackId;
+
+    @JsonProperty("source_mpack")
+    final String sourceMpack;
+
+    @JsonProperty("source_mpack_name")
+    final String sourceMpackName;
 
-    @JsonProperty("from_repository_version")
-    final String fromRepositoryVersion;
+    @JsonProperty("source_mpack_version")
+    final String sourceMpackVersion;
 
-    @JsonProperty("to_repository_id")
-    final long toRepositoryId;
+    @JsonProperty("target_mpack_id")
+    final long targetMpackId;
 
-    @JsonProperty("to_repository_version")
-    final String toRepositoryVersion;
+    @JsonProperty("target_mpack")
+    final String targetMpack;
+
+    @JsonProperty("target_mpack_name")
+    final String targetMpackName;
+
+    @JsonProperty("target_mpack_version")
+    final String targetMpackVersion;
 
     /**
      * Constructor.
      */
-    public RepositoryVersions(RepositoryVersionEntity from, RepositoryVersionEntity to) {
-      fromRepositoryId = from.getId();
-      fromRepositoryVersion = from.getVersion();
-
-      toRepositoryId = to.getId();
-      toRepositoryVersion = to.getVersion();
+    public RepositoryVersions(MpackEntity source, MpackEntity target) {
+      sourceMpackId = source.getId();
+      sourceMpackName = source.getMpackName();
+      sourceMpackVersion = source.getMpackVersion();
+      sourceMpack = new StackId(sourceMpackName, sourceMpackVersion).getStackId();
+
+      targetMpackId = target.getId();
+      targetMpackName = target.getMpackName();
+      targetMpackVersion = target.getMpackVersion();
+      targetMpack = new StackId(targetMpackName, targetMpackVersion).getStackId();
     }
   }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
index cb150a2..5a36876 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -189,9 +189,9 @@ public abstract class AmbariEvent {
     STALE_CONFIGS_UPDATE,
 
     /**
-     * Service component's repo has been changed..
+     * The mpack associated with a service group has changed.
      */
-    SERVICE_COMPONENT_REPO_CHANGE;
+    SERVICE_GROUP_MPACK_CHANGED;
   }
 
   /**
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterComponentsRepoChangedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupMpackChangedEvent.java
similarity index 81%
rename from ambari-server/src/main/java/org/apache/ambari/server/events/ClusterComponentsRepoChangedEvent.java
rename to ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupMpackChangedEvent.java
index 440562f..f7627f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterComponentsRepoChangedEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupMpackChangedEvent.java
@@ -17,9 +17,9 @@
  */
 package org.apache.ambari.server.events;
 
-public class ClusterComponentsRepoChangedEvent extends ClusterEvent {
+public class ServiceGroupMpackChangedEvent extends ClusterEvent {
 
-  public ClusterComponentsRepoChangedEvent(long clusterId) {
-    super(AmbariEventType.SERVICE_COMPONENT_REPO_CHANGE, clusterId);
+  public ServiceGroupMpackChangedEvent(long clusterId) {
+    super(AmbariEventType.SERVICE_GROUP_MPACK_CHANGED, clusterId);
   }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/UpgradeUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/UpgradeUpdateEvent.java
index 7fbd40d..c79d1db 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/UpgradeUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/UpgradeUpdateEvent.java
@@ -41,9 +41,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class UpgradeUpdateEvent extends AmbariUpdateEvent {
 
-  @JsonProperty("associated_version")
-  private String associatedVersion;
-
   @JsonProperty("cluster_id")
   private Long clusterId;
 
@@ -111,7 +108,6 @@ public class UpgradeUpdateEvent extends AmbariUpdateEvent {
     RequestEntity rentity = requestDAO.findByPK(upgradeEntity.getRequestId());
 
     upgradeUpdateEvent.setUpgradeId(upgradeEntity.getId());
-    upgradeUpdateEvent.setAssociatedVersion(upgradeEntity.getRepositoryVersion().getVersion());
     upgradeUpdateEvent.setClusterId(upgradeEntity.getClusterId());
     upgradeUpdateEvent.setDirection(upgradeEntity.getDirection());
     upgradeUpdateEvent.setDowngradeAllowed(upgradeEntity.isDowngradeAllowed());
@@ -155,14 +151,6 @@ public class UpgradeUpdateEvent extends AmbariUpdateEvent {
     return upgradeUpdateEvent;
   }
 
-  public String getAssociatedVersion() {
-    return associatedVersion;
-  }
-
-  public void setAssociatedVersion(String associatedVersion) {
-    this.associatedVersion = associatedVersion;
-  }
-
   public Long getClusterId() {
     return clusterId;
   }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MpackEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MpackEntity.java
index 42bf382..9faba2c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MpackEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MpackEntity.java
@@ -39,6 +39,8 @@ import org.apache.commons.lang.builder.EqualsBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.MoreObjects;
+
 /**
  * The {@link MpackEntity} class represents the mpack objects in the cluster.
  */
@@ -188,16 +190,12 @@ public class MpackEntity {
    */
   @Override
   public String toString() {
-    StringBuilder buffer = new StringBuilder("MpackEntity{");
-    buffer.append("id=").append(id);
-    if (null != registryId) {
-      buffer.append(", registryId=").append(registryId);
-    }
-    buffer.append(", mpackName=").append(mpackName);
-    buffer.append(", mpackVersion=").append(mpackVersion);
-    buffer.append(", mpackUri=").append(mpackUri);
-    buffer.append("}");
-    return buffer.toString();
+    return MoreObjects.toStringHelper(this).omitNullValues()
+        .add("id", id)
+        .add("registryId", registryId)
+        .add("name", mpackName)
+        .add("version", mpackVersion)
+        .add("uri", mpackUri).toString();
   }
 
   /**
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
index c555cb8..bda687a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
@@ -19,7 +19,6 @@ package org.apache.ambari.server.orm.entities;
 
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.StackId;
 
 @Deprecated
@@ -64,13 +63,6 @@ public class RepositoryVersionEntity {
   }
 
   /**
-   * @return the type
-   */
-  public RepositoryType getType() {
-    return null;
-  }
-
-  /**
    * @return the XML that is the basis for the version
    */
   public String getVersionXml() {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
index 04e29f8..27883c5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
@@ -38,6 +38,8 @@ import javax.persistence.UniqueConstraint;
 
 import org.apache.ambari.server.orm.dao.ServiceGroupDAO;
 
+import com.google.common.base.MoreObjects;
+
 
 @NamedQueries({
   @NamedQuery(name = "serviceGroupById", query =
@@ -167,6 +169,17 @@ public class ServiceGroupEntity {
   public int hashCode() {
     return Objects.hash(serviceGroupId, clusterId, serviceGroupName, stack);
   }
+  
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("clusterId", clusterId )
+        .add("id", serviceGroupId)
+        .add("name", serviceGroupName).toString();
+  }  
 
   public ClusterEntity getClusterEntity() {
     return clusterEntity;
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 b2209e9..bb99b72 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
@@ -18,7 +18,10 @@
 package org.apache.ambari.server.orm.entities;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
@@ -39,7 +42,6 @@ import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 import org.apache.commons.lang.builder.EqualsBuilder;
@@ -131,6 +133,12 @@ public class UpgradeEntity {
   private Short downgradeAllowed = 1;
 
   /**
+   * {@code true} if this upgrade is a revert, otherwise {@code false}
+   */
+  @Column(name = "is_revert", nullable = false)
+  private Short isRevert = 0;
+
+  /**
    * 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
@@ -149,10 +157,6 @@ public class UpgradeEntity {
   @Column(name = "revert_allowed", nullable = false)
   private Short revertAllowed = 0;
 
-  @Column(name="orchestration", nullable = false)
-  @Enumerated(value = EnumType.STRING)
-  private RepositoryType orchestration = RepositoryType.STANDARD;
-
   /**
    * {@code true} if the upgrade has been marked as suspended.
    */
@@ -263,6 +267,25 @@ public class UpgradeEntity {
   }
 
   /**
+   * Gets whether this upgrade is a revert.
+   *
+   * @return {@code true} if this is a revert, {@code false} otherwise.
+   */
+  public Boolean isRevert() {
+    return isRevert != null ? (isRevert != 0) : null;
+  }
+
+  /**
+   * Sets whether this upgrade is a revert.
+   *
+   * @param isRevert
+   *          {@code true} if this is a revert, {@code false} otherwise.
+   */
+  public void setIsRevert(boolean isRevert) {
+    this.isRevert = (!isRevert ? (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
@@ -400,56 +423,6 @@ public class UpgradeEntity {
   }
 
   /**
-   * 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.
-   *
-   * @return the repository version being upgraded to or downgraded from (never
-   *         {@code null}).
-   */
-  public RepositoryVersionEntity getRepositoryVersion() {
-    return null;
-  }
-
-  /**
-   * Sets the repository version for this upgrade. This value will change
-   * depending on the direction of the upgrade.
-   * <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.
-   *
-   * @param repositoryVersion
-   *          the repository version being upgraded to or downgraded from (not
-   *          {@code null}).
-   */
-  public void setRepositoryVersion(RepositoryVersionEntity repositoryVersion) {
-  }
-
-  /**
-   * Sets the orchestration for the upgrade.  Only different when an upgrade is a revert of a patch.
-   * In that case, the orchestration is set to PATCH even if the target repository is type STANDARD.
-   *
-   * @param type  the orchestration
-   */
-  public void setOrchestration(RepositoryType type) {
-    orchestration = type;
-  }
-
-  /**
-   * @return  the orchestration type
-   */
-  public RepositoryType getOrchestration() {
-    return orchestration;
-  }
-
-  /**
    * {@inheritDoc}
    */
   @Override
@@ -483,4 +456,64 @@ public class UpgradeEntity {
         upgradePackage);
   }
 
+  /**
+   * Gets the mpacks which are participating in the upgrade.
+   *
+   * @return the set of mpacks in this upgrade.
+   */
+  public Set<MpackEntity> getSourceMpacks() {
+    List<UpgradeHistoryEntity> historyEntities = getHistory();
+
+    LinkedHashSet<MpackEntity> mpacks = historyEntities.stream().map(
+        history -> history.getSourceMpackEntity()).collect(
+            Collectors.toCollection(LinkedHashSet::new));
+
+    return mpacks;
+  }
+
+  /**
+   * Gets the mpack stack IDs which are participating in the upgrade.
+   *
+   * @return the set of mpacks in this upgrade.
+   */
+  public Set<String> getSourceMpackStacks() {
+    List<UpgradeHistoryEntity> historyEntities = getHistory();
+
+    LinkedHashSet<String> mpacks = historyEntities.stream().map(
+        history -> history.getSourceMpackEntity().getStackId().toString()).collect(
+            Collectors.toCollection(LinkedHashSet::new));
+
+    return mpacks;
+  }
+
+  /**
+   * Gets the mpacks which are participating in the upgrade.
+   *
+   * @return the target set of mpacks in this upgrade.
+   */
+  public Set<MpackEntity> getTargetMpack() {
+    List<UpgradeHistoryEntity> historyEntities = getHistory();
+
+    LinkedHashSet<MpackEntity> mpacks = historyEntities.stream().map(
+        history -> history.getTargetMpackEntity()).collect(
+            Collectors.toCollection(LinkedHashSet::new));
+
+    return mpacks;
+  }
+
+  /**
+   * Gets the mpack names which are participating in the upgrade.
+   *
+   * @return the target set of mpacks in this upgrade.
+   */
+  public Set<String> getTargetMpackStacks() {
+    List<UpgradeHistoryEntity> historyEntities = getHistory();
+
+    LinkedHashSet<String> mpacks = historyEntities.stream().map(
+        history -> history.getTargetMpackEntity().getStackId().toString()).collect(
+            Collectors.toCollection(LinkedHashSet::new));
+
+    return mpacks;
+  }
+
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeHistoryEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeHistoryEntity.java
index 75df347..56a4a43 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeHistoryEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeHistoryEntity.java
@@ -23,6 +23,7 @@ import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.Table;
@@ -31,6 +32,7 @@ import javax.persistence.UniqueConstraint;
 
 import org.apache.commons.lang.builder.EqualsBuilder;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 
 /**
@@ -41,7 +43,7 @@ import com.google.common.base.Objects;
 @Table(
     name = "upgrade_history",
     uniqueConstraints = @UniqueConstraint(
-        columnNames = { "upgrade_id", "component_name", "service_name" }))
+        columnNames = { "upgrade_id", "service_group_id" }))
 @TableGenerator(
     name = "upgrade_history_id_generator",
     table = "ambari_sequences",
@@ -70,110 +72,83 @@ public class UpgradeHistoryEntity {
   @JoinColumn(name = "upgrade_id", nullable = false)
   private UpgradeEntity upgrade;
 
-  @Column(name = "service_name", nullable = false, insertable = true, updatable = true)
-  private String serviceName;
+  @Column(name = "source_mpack_id", nullable = false, insertable = false, updatable = false)
+  private Long sourceMpackId;
 
-  @Column(name = "component_name", nullable = false, insertable = true, updatable = true)
-  private String componentName;
+  @ManyToOne()
+  @JoinColumn(name = "source_mpack_id", referencedColumnName = "id")
+  private MpackEntity sourceMpackEntity;
 
-  /**
-   * @return the id
-   */
-  public Long getId() {
-    return id;
-  }
+  @Column(name = "target_mpack_id", nullable = false, insertable = false, updatable = false)
+  private Long targetMpackId;
 
-  /**
-   * Gets the ID of the upgrade associated with this historical entry.
-   *
-   * @return the upgrade ID (never {@code null}).
-   */
-  public Long getUpgradeId() {
-    return upgradeId;
-  }
+  @ManyToOne()
+  @JoinColumn(name = "target_mpack_id", referencedColumnName = "id")
+  private MpackEntity targetMpackEntity;
 
-  /**
-   * @return
-   */
-  public String getServiceName() {
-    return serviceName;
-  }
-
-  /**
-   * @param serviceName
-   */
-  public void setServiceName(String serviceName) {
-    this.serviceName = serviceName;
-  }
+  @Column(name = "service_group_id", nullable = false, insertable = false, updatable = false)
+  private Long serviceGroupId;
 
-  /**
-   * @return
-   */
-  public String getComponentName() {
-    return componentName;
-  }
+  @ManyToOne()
+  @JoinColumn(name = "service_group_id", referencedColumnName = "id")
+  private ServiceGroupEntity serviceGroupEntity;
 
   /**
-   * @param componentName
+   * Constructor.
+   *
    */
-  public void setComponentName(String componentName) {
-    this.componentName = componentName;
+  UpgradeHistoryEntity() {
   }
 
-  /**
-   * Gets the repository that the upgrade is coming from.
-   *
-   * @return the repository that the upgrade is coming from (not {@code null}).
-   */
-  public RepositoryVersionEntity getFromReposistoryVersion() {
-    return null;
+  public UpgradeHistoryEntity(UpgradeEntity upgrade, ServiceGroupEntity serviceGroup,
+      MpackEntity sourceMpack, MpackEntity targetMpack) {
+    this.upgrade = upgrade;
+    serviceGroupEntity = serviceGroup;
+    sourceMpackEntity = sourceMpack;
+    targetMpackEntity = targetMpack;
   }
 
   /**
-   * Sets the repository that the services in the upgrade are CURRENT on.
-   *
-   * @param repositoryVersionEntity
-   *          the repository entity (not {@code null}).
+   * @return the id
    */
-  public void setFromRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
+  public Long getId() {
+    return id;
   }
 
   /**
-   * Gets the target repository version for this upgrade.
+   * Gets the upgrade that the history entry is for.
    *
-   * @return the target repository for the services in the upgrade (not
-   *         {@code null}).
+   * @return the upgrade
    */
-  public RepositoryVersionEntity getTargetRepositoryVersion() {
-    return null;
+  public UpgradeEntity getUpgrade() {
+    return upgrade;
   }
 
   /**
-   * Gets the version of the target repository.
+   * Gets the source mpack that the upgrade is coming from.
    *
-   * @return the target version string (never {@code null}).
-   * @see #getTargetRepositoryVersion()
+   * @return the sourceMpackEntity
    */
-  public String getTargetVersion() {
-    return null;
+  public MpackEntity getSourceMpackEntity() {
+    return sourceMpackEntity;
   }
 
   /**
-   * Sets the target repository of the upgrade.
+   * Gets the target mpack that the upgrade is moving to.
    *
-   * @param repositoryVersionEntity
-   *          the target repository (not {@code null}).
+   * @return the targetMpackEntity
    */
-  public void setTargetRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
+  public MpackEntity getTargetMpackEntity() {
+    return targetMpackEntity;
   }
 
   /**
-   * Sets the associated upgrade entity.
+   * The service group which this upgrade history entry is for.
    *
-   * @param upgrade
+   * @return the service group.
    */
-  public void setUpgrade(UpgradeEntity upgrade) {
-    this.upgrade = upgrade;
+  public ServiceGroupEntity getServiceGroupEntity() {
+    return serviceGroupEntity;
   }
 
   /**
@@ -191,10 +166,10 @@ public class UpgradeHistoryEntity {
 
     UpgradeHistoryEntity that = (UpgradeHistoryEntity) o;
     return new EqualsBuilder()
-        .append(id, that.id)
         .append(upgradeId, that.upgradeId)
-        .append(serviceName, that.serviceName)
-        .append(componentName, that.componentName)
+        .append(serviceGroupEntity, that.serviceGroupEntity)
+        .append(sourceMpackEntity, that.sourceMpackEntity)
+        .append(targetMpackEntity, that.targetMpackEntity)
         .isEquals();
   }
 
@@ -203,7 +178,7 @@ public class UpgradeHistoryEntity {
    */
   @Override
   public int hashCode() {
-    return Objects.hashCode(id, upgradeId, serviceName, componentName);
+    return Objects.hashCode(upgradeId, serviceGroupEntity, sourceMpackEntity, targetMpackEntity);
   }
 
   /**
@@ -211,10 +186,11 @@ public class UpgradeHistoryEntity {
    */
   @Override
   public String toString() {
-    return Objects.toStringHelper(this)
+    return MoreObjects.toStringHelper(this)
         .add("id", id)
         .add("upgradeId", upgradeId)
-        .add("serviceName", serviceName)
-        .add("componentName", componentName).toString();
+        .add("serviceGroupId", serviceGroupId)
+        .add("sourceMpack", sourceMpackEntity)
+        .add("targetMpack", targetMpackEntity).toString();
   }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/ServerActionExecutor.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/ServerActionExecutor.java
index e219dc3..405d60a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/ServerActionExecutor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/ServerActionExecutor.java
@@ -50,8 +50,9 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.security.authorization.internal.InternalAuthenticationToken;
 import org.apache.ambari.server.state.ServiceInfo;
-import org.apache.ambari.server.state.UpgradeContext.UpgradeServiceSummary;
+import org.apache.ambari.server.state.UpgradeContext.UpgradeServiceGroupSummary;
 import org.apache.ambari.server.state.UpgradeContext.UpgradeSummary;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -516,25 +517,28 @@ public class ServerActionExecutor {
           if (actionClassname == null) {
             throw new AmbariException("Missing action classname for server action");
           } else {
-            Map<String, ServiceInfo> services = new HashMap<String, ServiceInfo>();
+            Map<String, ServiceInfo> services = new HashMap<>();
             UpgradeSummary upgradeSummary = executionCommand.getUpgradeSummary();
             if (upgradeSummary != null) {
-              Map<String, UpgradeServiceSummary> upgradeServiceSummaries = upgradeSummary.services;
-              LOG.debug("UpgradeServiceSummary: " + upgradeServiceSummaries);
+              Map<String, UpgradeServiceGroupSummary> upgradeServiceGroupSummaries = upgradeSummary.serviceGroups;
               AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
               AmbariMetaInfo ambariMetaInfo = ambariManagementController.getAmbariMetaInfo();
               String serviceName = executionCommand.getServiceName();
-              if (serviceName != null && !serviceName.isEmpty()){
-                LOG.info(String.format("Server action %s is associated with service %s", actionClassname, serviceName));
+              String serviceGroupName = executionCommand.getServiceGroupName();
+
+              if (StringUtils.isNotBlank(serviceName) && StringUtils.isNotBlank(serviceGroupName)){
+                LOG.info("Server action {} is associated with service {}", actionClassname, serviceName);
                 //Execution stage of a given service, only need to examine stack information for this one service
-                UpgradeServiceSummary serviceSummary = upgradeServiceSummaries.get(serviceName);
-                addServiceInfo(services, ambariMetaInfo, serviceSummary.sourceStackId, serviceName);
+                UpgradeServiceGroupSummary serviceGroupSummary = upgradeServiceGroupSummaries.get(serviceGroupName);
+                addServiceInfo(services, ambariMetaInfo, serviceGroupSummary.targetStack, serviceName);
               } else {
                 LOG.info(String.format("Server action %s is not associated with a service", actionClassname));
                 //Load all Jars
-                for(String key: upgradeServiceSummaries.keySet()){
-                  UpgradeServiceSummary serviceSummary = upgradeServiceSummaries.get(key);
-                  addServiceInfo(services, ambariMetaInfo, serviceSummary.sourceStackId, key);
+                for(String serviceGroupKey: upgradeServiceGroupSummaries.keySet()){
+                  UpgradeServiceGroupSummary serviceGroupSummary = upgradeServiceGroupSummaries.get(serviceGroupKey);
+                  for (String serviceNameKey : serviceGroupSummary.services.keySet()) {
+                    addServiceInfo(services, ambariMetaInfo, serviceGroupSummary.targetStack, serviceNameKey);
+                  }
                 }
               }
               LOG.info(String.format("Attempt to load server action classes from %s", services.keySet().toString()));
@@ -571,7 +575,7 @@ public class ServerActionExecutor {
     private List<String> getStackInfo(String stackId) {
       LOG.debug(String.format("Stack id: %s", stackId));
       StringTokenizer tokens = new StringTokenizer(stackId, "-");
-      List<String> info = new ArrayList<String>();
+      List<String> info = new ArrayList<>();
       while (tokens.hasMoreElements()) {
         info.add((String)tokens.nextElement());
       }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java
index 5be33a1..67fc467 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java
@@ -37,7 +37,6 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.metadata.ClusterMetadataGenerator;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.serveraction.ServerAction;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Config;
@@ -45,8 +44,10 @@ import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.ConfigMergeHelper;
 import org.apache.ambari.server.state.ConfigMergeHelper.ThreeWayValue;
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Mpack;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue;
@@ -201,10 +202,14 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
       serviceName = commandParameters.get(ConfigureTask.PARAMETER_ASSOCIATED_SERVICE);
     }
 
-    RepositoryVersionEntity sourceRepoVersion = upgradeContext.getSourceRepositoryVersion(serviceName);
-    RepositoryVersionEntity targetRepoVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
-    StackId sourceStackId = sourceRepoVersion.getStackId();
-    StackId targetStackId = targetRepoVersion.getStackId();
+    // this is wrong since it gets the service group by service name
+    long serviceGroupId = cluster.getService(serviceName).getServiceGroupId();
+    ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupId);
+    Mpack sourceMpack = upgradeContext.getSourceMpack(serviceGroup);
+    Mpack targetMpack = upgradeContext.getTargetMpack(serviceGroup);
+
+    StackId sourceStackId = sourceMpack.getStackId();
+    StackId targetStackId = targetMpack.getStackId();
 
     // extract setters
     List<ConfigurationKeyValue> keyValuePairs = Collections.emptyList();
@@ -551,8 +556,8 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     // !!! values are different and within the same stack.  create a new
     // config and service config version
     Direction direction = upgradeContext.getDirection();
-    String serviceVersionNote = String.format("%s %s %s", direction.getText(true),
-        direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion());
+    String serviceVersionNote = String.format("%s %s: \n%s", direction.getText(true),
+        direction.getPreposition(), upgradeContext.getServiceGroupDisplayableSummary());
 
     String auditName = getExecutionCommand().getRoleParams().get(ServerAction.ACTION_USER_NAME);
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
index ad031c8..aa7e6b2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
@@ -26,11 +26,12 @@ import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ConfigurationRequest;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Mpack;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask;
@@ -115,10 +116,14 @@ public class CreateAndConfigureAction extends ConfigureAction {
       serviceName = commandParameters.get(CreateAndConfigureTask.PARAMETER_ASSOCIATED_SERVICE);
     }
 
-    RepositoryVersionEntity sourceRepoVersion = upgradeContext.getSourceRepositoryVersion(serviceName);
-    RepositoryVersionEntity targetRepoVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
-    StackId sourceStackId = sourceRepoVersion.getStackId();
-    StackId targetStackId = targetRepoVersion.getStackId();
+    // this is wrong since it gets the service group by service name
+    long serviceGroupId = cluster.getService(serviceName).getServiceGroupId();
+    ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupId);
+    Mpack sourceMpack = upgradeContext.getSourceMpack(serviceGroup);
+    Mpack targetMpack = upgradeContext.getTargetMpack(serviceGroup);
+
+    StackId sourceStackId = sourceMpack.getStackId();
+    StackId targetStackId = targetMpack.getStackId();
 
     if (!sourceStackId.equals(targetStackId)){
       return createCommandReport(0, HostRoleStatus.FAILED, "{}", "",
@@ -150,8 +155,8 @@ public class CreateAndConfigureAction extends ConfigureAction {
         }
       }
 
-      String serviceVersionNote = String.format("%s %s %s", direction.getText(true),
-          direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion());
+      String serviceVersionNote = String.format("%s %s: \n%s", direction.getText(true),
+          direction.getPreposition(), upgradeContext.getServiceGroupDisplayableSummary());
 
       m_configHelper.createConfigType(cluster, targetStackId,
           m_controller,
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 cb9dbfa..8117a00 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
@@ -21,7 +21,6 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.text.MessageFormat;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -34,19 +33,20 @@ import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.events.StackUpgradeFinishEvent;
 import org.apache.ambari.server.events.publishers.VersionEventPublisher;
-import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
 import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
-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;
+import org.apache.ambari.server.state.ModuleComponent;
+import org.apache.ambari.server.state.Mpack;
+import org.apache.ambari.server.state.Mpack.MpackChangeSummary;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeState;
@@ -93,9 +93,6 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
     }
   }
 
-  @Inject
-  private RoleCommandOrderProvider roleCommandOrderProvider;
-
   /**
    * Execution path for upgrade.
    * @return the command report
@@ -104,43 +101,32 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
     throws AmbariException, InterruptedException {
 
     Direction direction = upgradeContext.getDirection();
-    RepositoryType repositoryType = upgradeContext.getOrchestrationType();
 
     StringBuilder outSB = new StringBuilder();
     StringBuilder errSB = new StringBuilder();
 
     try {
       Cluster cluster = upgradeContext.getCluster();
-      RepositoryVersionEntity repositoryVersion = upgradeContext.getRepositoryVersion();
-      String version = repositoryVersion.getVersion();
-
-      String message;
-      if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) {
-        message = MessageFormat.format("Finalizing the upgrade to {0} for all cluster services.", version);
-      } else {
-        Set<String> servicesInUpgrade = upgradeContext.getSupportedServices();
-
-        message = MessageFormat.format(
-            "Finalizing the upgrade to {0} for the following services: {1}",
-            version, StringUtils.join(servicesInUpgrade, ','));
-      }
+      Map<ServiceGroup, MpackChangeSummary> serviceGroupChanges = upgradeContext.getServiceGroups();
+      for (ServiceGroup serviceGroup : serviceGroupChanges.keySet()) {
+        MpackChangeSummary mpackChangeSummary = serviceGroupChanges.get(serviceGroup);
 
-      outSB.append(message).append(System.lineSeparator());
+        String message = MessageFormat.format(
+            "Finalizing the upgrade to {0} for the service group {1}",
+            mpackChangeSummary.getTarget().getVersion(), serviceGroup.getServiceGroupName());
+
+        outSB.append(message).append(System.lineSeparator());
+      }
 
       // iterate through all host components and make sure that they are on the
       // correct version; if they are not, then this will throw an exception
       Set<InfoTuple> errors = validateComponentVersions(upgradeContext);
       if (!errors.isEmpty()) {
         StrBuilder messageBuff = new StrBuilder(String.format(
-            "The following %d host component(s) "
-                + "have not been upgraded to version %s. Please install and upgrade "
-                + "the Stack Version on those hosts and try again.\nHost components:",
-            errors.size(), version)).append(System.lineSeparator());
-
-        for (InfoTuple error : errors) {
-          messageBuff.append(String.format("%s on host %s\n", error.componentName, error.hostName));
-        }
+            "The following %d host component(s) have not been upgraded to their expected version:")).append(
+                System.lineSeparator());
 
+        errors.stream().forEach(infoTuple -> messageBuff.append(infoTuple));
         throw new AmbariException(messageBuff.toString());
       }
 
@@ -153,13 +139,9 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
         }
       }
 
-      if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) {
-        outSB.append(String.format("Finalizing the version for cluster %s.\n", cluster.getClusterName()));
-        cluster.setCurrentStackVersion(cluster.getDesiredStackVersion());
-      }
-
       // mark revertable
-      if (repositoryType.isRevertable() && direction == Direction.UPGRADE) {
+      boolean revertable = false;
+      if (revertable && direction == Direction.UPGRADE) {
         UpgradeEntity upgrade = cluster.getUpgradeInProgress();
         upgrade.setRevertAllowed(true);
         upgrade = m_upgradeDAO.merge(upgrade);
@@ -171,8 +153,11 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
       // the upgrade is done!
       versionEventPublisher.publish(new StackUpgradeFinishEvent(cluster));
 
-      message = String.format("The upgrade to %s has completed.", version);
-      outSB.append(message).append(System.lineSeparator());
+      StringBuilder finalMessage = new StringBuilder("The upgrade for the following service groups has completed.");
+      finalMessage.append(System.lineSeparator());
+      finalMessage.append(upgradeContext.getServiceGroupDisplayableSummary());
+
+      outSB.append(finalMessage).append(System.lineSeparator());
       return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", outSB.toString(), errSB.toString());
     } catch (Exception e) {
       errSB.append(e.getMessage());
@@ -195,47 +180,27 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
 
     try {
       Cluster cluster = upgradeContext.getCluster();
-      RepositoryVersionEntity downgradeFromRepositoryVersion = upgradeContext.getRepositoryVersion();
-      String downgradeFromVersion = downgradeFromRepositoryVersion.getVersion();
-      Set<String> servicesInUpgrade = upgradeContext.getSupportedServices();
-
-      String message;
-
-      if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) {
-        message = MessageFormat.format(
-            "Finalizing the downgrade from {0} for all cluster services.",
-            downgradeFromVersion);
-      } else {
-        message = MessageFormat.format(
-            "Finalizing the downgrade from {0} for the following services: {1}",
-            downgradeFromVersion, StringUtils.join(servicesInUpgrade, ','));
-      }
+      Map<ServiceGroup, MpackChangeSummary> serviceGroupChanges = upgradeContext.getServiceGroups();
+      for (ServiceGroup serviceGroup : serviceGroupChanges.keySet()) {
+        MpackChangeSummary mpackChangeSummary = serviceGroupChanges.get(serviceGroup);
+
+        String message = MessageFormat.format(
+            "Finalizing the downgrade from {0} for the service group {1}",
+            mpackChangeSummary.getTarget().getVersion(), serviceGroup.getServiceGroupName());
 
-      outSB.append(message).append(System.lineSeparator());
+        outSB.append(message).append(System.lineSeparator());
+      }
 
       // iterate through all host components and make sure that they are on the
       // correct version; if they are not, then this will throw an exception
       Set<InfoTuple> errors = validateComponentVersions(upgradeContext);
       if (!errors.isEmpty()) {
         StrBuilder messageBuff = new StrBuilder(String.format(
-            "The following %d host component(s) have not been downgraded to their desired versions:",
-            errors.size())).append(System.lineSeparator());
+            "The following %d host component(s) have not been downgraded to their expected version:")).append(
+                System.lineSeparator());
 
-        for (InfoTuple error : errors) {
-          messageBuff.append(String.format("%s: %s (current = %s, desired = %s)", error.hostName,
-              error.componentName, error.currentVersion, error.targetVersion));
-
-          messageBuff.append(System.lineSeparator());
-        }
-
-        throw new AmbariException(messageBuff.toString());
-      }
-
-      // for every repository being downgraded to, ensure the host versions are correct
-      Map<String, RepositoryVersionEntity> targetVersionsByService = upgradeContext.getTargetVersions();
-      Set<RepositoryVersionEntity> targetRepositoryVersions = new HashSet<>();
-      for (String service : targetVersionsByService.keySet()) {
-        targetRepositoryVersions.add(targetVersionsByService.get(service));
+        errors.stream().forEach(infoTuple -> messageBuff.append(infoTuple));
+        outSB.append(messageBuff.toString()).append(System.lineSeparator());
       }
 
       // do some cleanup like resetting the upgrade state
@@ -248,18 +213,24 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
       }
 
       // remove any configurations for services which crossed a stack boundary
-      for (String serviceName : servicesInUpgrade) {
-        RepositoryVersionEntity sourceRepositoryVersion = upgradeContext.getSourceRepositoryVersion(serviceName);
-        RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
-        StackId sourceStackId = sourceRepositoryVersion.getStackId();
-        StackId targetStackId = targetRepositoryVersion.getStackId();
-        // only work with configurations when crossing stacks
-        if (!sourceStackId.equals(targetStackId)) {
-          outSB.append(
-              String.format("Removing %s configurations for %s", sourceStackId,
-                  serviceName)).append(System.lineSeparator());
-          //TODO pass serviceGroupName
-          cluster.removeConfigurations(sourceStackId, cluster.getService(null, serviceName).getServiceId());
+      for (ServiceGroup serviceGroup : serviceGroupChanges.keySet()) {
+        MpackChangeSummary mpackChangeSummary = serviceGroupChanges.get(serviceGroup);
+        Mpack sourceMpack = mpackChangeSummary.getSource();
+        Mpack targetMpack = mpackChangeSummary.getTarget();
+        StackId sourceStackId = sourceMpack.getStackId();
+        StackId targetStackId = targetMpack.getStackId();
+
+        for (Service service : serviceGroup.getServices()) {
+          // only work with configurations when crossing stacks
+          if (!sourceStackId.equals(targetStackId)) {
+            outSB.append(
+                String.format("Removing %s configurations for %s", sourceStackId,
+                    service.getName())).append(System.lineSeparator());
+
+            cluster.removeConfigurations(sourceStackId,
+                cluster.getService(serviceGroup.getServiceGroupName(),
+                    service.getName()).getServiceId());
+          }
         }
       }
 
@@ -270,8 +241,11 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
       // Reset upgrade state
       cluster.setUpgradeEntity(null);
 
-      message = String.format("The downgrade from %s has completed.", downgradeFromVersion);
-      outSB.append(message).append(System.lineSeparator());
+      StringBuilder finalMessage = new StringBuilder("The downgrade for the following service groups has completed.");
+      finalMessage.append(System.lineSeparator());
+      finalMessage.append(upgradeContext.getServiceGroupDisplayableSummary());
+
+      outSB.append(finalMessage).append(System.lineSeparator());
 
       return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", outSB.toString(), errSB.toString());
     } catch (Exception e) {
@@ -297,34 +271,36 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
 
     Set<InfoTuple> errors = new TreeSet<>();
 
-    Cluster cluster = upgradeContext.getCluster();
-    Set<String> servicesParticipating = upgradeContext.getSupportedServices();
-    for (String serviceName : servicesParticipating) {
-      Service service = cluster.getService(serviceName);
-      RepositoryVersionEntity repositoryVersionEntity = upgradeContext.getTargetRepositoryVersion(serviceName);
-      StackId targetStackId = repositoryVersionEntity.getStackId();
-      String targetVersion = repositoryVersionEntity.getVersion();
-
-      for (ServiceComponent serviceComponent : service.getServiceComponents().values()) {
-        for (ServiceComponentHost serviceComponentHost : serviceComponent.getServiceComponentHosts().values()) {
-          ComponentInfo componentInfo = ambariMetaInfo.getComponent(targetStackId.getStackName(),
-                  targetStackId.getStackVersion(), service.getServiceType(), serviceComponent.getName());
-
-          if (!componentInfo.isVersionAdvertised()) {
-            continue;
-          }
+    Map<ServiceGroup, MpackChangeSummary> serviceGroupChanges = upgradeContext.getServiceGroups();
+    for (ServiceGroup serviceGroup : serviceGroupChanges.keySet()) {
+      MpackChangeSummary mpackChangeSummary = serviceGroupChanges.get(serviceGroup);
+      Mpack targetMpack = mpackChangeSummary.getTarget();
+      StackId targetStackId = targetMpack.getStackId();
 
+      for (Service service : serviceGroup.getServices()) {
+        for (ServiceComponent serviceComponent : service.getServiceComponents().values()) {
+          for (ServiceComponentHost serviceComponentHost : serviceComponent.getServiceComponentHosts().values()) {
+            ComponentInfo componentInfo = ambariMetaInfo.getComponent(targetStackId.getStackName(),
+                    targetStackId.getStackVersion(), service.getServiceType(), serviceComponent.getName());
 
-          if (!StringUtils.equals(targetVersion, serviceComponentHost.getVersion())) {
-            errors.add(new InfoTuple(service.getName(), serviceComponent.getName(),
-                    serviceComponentHost.getHostName(), serviceComponentHost.getVersion(),
-                    targetVersion));
+            if (!componentInfo.isVersionAdvertised()) {
+              continue;
+            }
 
+            ModuleComponent moduleComponent = targetMpack.getModuleComponent(
+                serviceComponent.getServiceName(), serviceComponent.getName());
+
+            if (!StringUtils.equals(moduleComponent.getVersion(), serviceComponentHost.getVersion())) {
+              InfoTuple error = new InfoTuple(service.getName(), serviceComponent.getName(),
+                  serviceComponentHost.getHostName(), serviceComponentHost.getVersion(),
+                  moduleComponent.getVersion());
+
+              errors.add(error);
+            }
           }
         }
       }
     }
-
     return errors;
   }
 
@@ -401,15 +377,14 @@ public class FinalizeUpgradeAction extends AbstractUpgradeServerAction {
     }
 
     /**
+     * Used for outputting error messages during upgrade.
+     * <p/>
      * {@inheritDoc}
      */
     @Override
     public String toString() {
-      return com.google.common.base.Objects.toStringHelper(this)
-          .add("host", hostName)
-          .add("component", componentName)
-          .add("current", currentVersion)
-          .add("target", targetVersion).toString();
+      return String.format("%s on host %s reported %s when %s was expected\n", componentName,
+          hostName, currentVersion, targetVersion);
     }
   }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FixNotebookStorage.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FixNotebookStorage.java
deleted file mode 100644
index b0e3f89..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FixNotebookStorage.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.serveraction.upgrades;
-
-import java.util.Map;
-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.orm.entities.RepositoryVersionEntity;
-import org.apache.ambari.server.orm.entities.UpgradeEntity;
-import org.apache.ambari.server.serveraction.AbstractServerAction;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.utils.VersionUtils;
-
-import com.google.inject.Inject;
-
-/**
- * During stack upgrade,
- * if stack HDP >=2.6.3 and old value org.apache.zeppelin.notebook.repo.VFSNotebookRepo
- * update zeppelin.notebook.storage
- * to org.apache.zeppelin.notebook.repo.FileSystemNotebookRepo
- * if stack HDP >=2.6.3 and no zeppelin.config.fs.dir
- * set zeppelin.config.fs.dir to conf
- */
-public class FixNotebookStorage extends AbstractServerAction {
-
-  public static final String ZEPPELIN_NOTEBOOK_STORAGE = "zeppelin.notebook.storage";
-  public static final String ZEPPELIN_CONF = "zeppelin-config";
-  public static final String ORG_APACHE_ZEPPELIN_NOTEBOOK_REPO_VFSNOTEBOOK_REPO = "org.apache.zeppelin.notebook.repo.VFSNotebookRepo";
-  public static final String REC_VERSION = "2.6.3.0";
-  public static final String ORG_APACHE_ZEPPELIN_NOTEBOOK_REPO_FILE_SYSTEM_NOTEBOOK_REPO = "org.apache.zeppelin.notebook.repo.FileSystemNotebookRepo";
-  public static final String ZEPPELIN_CONFIG_FS_DIR = "zeppelin.config.fs.dir";
-  public static final String ZEPPELIN_CONFIG_FS_DIR_VALUE = "conf";
-
-
-  @Inject
-  private Clusters clusters;
-
-  @Override
-  public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext)
-      throws AmbariException, InterruptedException {
-    String clusterName = getExecutionCommand().getClusterName();
-    Cluster cluster = clusters.getCluster(clusterName);
-    UpgradeEntity upgrade = cluster.getUpgradeInProgress();
-    RepositoryVersionEntity repositoryVersionEntity = upgrade.getRepositoryVersion();
-    String targetVersion = repositoryVersionEntity.getVersion();
-
-    Config config = cluster.getDesiredConfigByType(ZEPPELIN_CONF);
-    if (config == null || VersionUtils.compareVersions(targetVersion, REC_VERSION) < 0) {
-      return createCommandReport(0, HostRoleStatus.COMPLETED, "{}",
-          String.format("%s change not required", ZEPPELIN_NOTEBOOK_STORAGE), "");
-    }
-    Map<String, String> properties = config.getProperties();
-    String oldContent = properties.get(ZEPPELIN_NOTEBOOK_STORAGE);
-    String newContent = ORG_APACHE_ZEPPELIN_NOTEBOOK_REPO_FILE_SYSTEM_NOTEBOOK_REPO;
-
-    String output = "";
-    if (!properties.containsKey(ZEPPELIN_CONFIG_FS_DIR)) {
-      properties.put(ZEPPELIN_CONFIG_FS_DIR, ZEPPELIN_CONFIG_FS_DIR_VALUE);
-      output += String.format("set %s to %s\n",
-          ZEPPELIN_NOTEBOOK_STORAGE, ORG_APACHE_ZEPPELIN_NOTEBOOK_REPO_FILE_SYSTEM_NOTEBOOK_REPO);
-    }
-    if (ORG_APACHE_ZEPPELIN_NOTEBOOK_REPO_VFSNOTEBOOK_REPO.equals(oldContent)) {
-      properties.put(ZEPPELIN_NOTEBOOK_STORAGE, newContent);
-      output += String.format("set %s to %s\n",
-          ZEPPELIN_CONFIG_FS_DIR, ZEPPELIN_CONFIG_FS_DIR_VALUE);
-    }
-    if (output.isEmpty()) {
-      output = "change not required";
-    }
-    config.setProperties(properties);
-    config.save();
-    return createCommandReport(0, HostRoleStatus.COMPLETED, "{}",
-        output, "");
-  }
-}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java
index e570f68..1bbc76b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java
@@ -33,6 +33,8 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
@@ -44,7 +46,6 @@ import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.KerberosKeytabDAO;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
 import org.apache.ambari.server.orm.entities.HostEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.serveraction.kerberos.PreconfigureServiceType;
 import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
 import org.apache.ambari.server.state.Cluster;
@@ -75,6 +76,9 @@ import com.google.inject.Inject;
  * Kerberos descriptors, flagged for pre-configuring, during stack upgrades in order to prevent service
  * restarts when the flagged services are installed.
  */
+@Experimental(
+    feature = ExperimentalFeature.MPACK_UPGRADES,
+    comment = "Needs to move away from stacks and to service groups & mpacks")
 public class PreconfigureKerberosAction extends AbstractUpgradeServerAction {
   static final String UPGRADE_DIRECTION_KEY = "upgrade_direction";
 
@@ -264,18 +268,15 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction {
    * @return the target {@link StackId}
    * @throws AmbariException if multiple stack id's are detected
    */
+  @Experimental(
+      feature = ExperimentalFeature.MPACK_UPGRADES,
+      comment = "Needs to move away from stacks and to service groups & mpacks")
   private StackId getTargetStackId(Cluster cluster) throws AmbariException {
     UpgradeContext upgradeContext = getUpgradeContext(cluster);
 
     // !!! FIXME in a per-service view, what does this become?
     Set<StackId> stackIds = new HashSet<>();
 
-    for (Service service : cluster.getServices()) {
-      RepositoryVersionEntity targetRepoVersion = upgradeContext.getTargetRepositoryVersion(service.getName());
-      StackId targetStackId = targetRepoVersion.getStackId();
-      stackIds.add(targetStackId);
-    }
-
     if (1 != stackIds.size()) {
       throw new AmbariException("Services are deployed from multiple stacks and cannot determine a unique one.");
     }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredMpackAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredMpackAction.java
new file mode 100644
index 0000000..9af8222
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredMpackAction.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.serveraction.upgrades;
+
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
+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.state.ServiceGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link UpdateDesiredMpackAction} is used during an upgrade to change the
+ * association of a {@link ServiceGroup}'s management pack.
+ */
+@Experimental(feature = ExperimentalFeature.MPACK_UPGRADES)
+public class UpdateDesiredMpackAction extends AbstractUpgradeServerAction {
+
+  /**
+   * Logger.
+   */
+  private static final Logger LOG = LoggerFactory.getLogger(UpdateDesiredMpackAction.class);
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext)
+      throws AmbariException, InterruptedException {
+    return createCommandReport(-1, HostRoleStatus.FAILED, "{}", "", "");
+  }
+}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredRepositoryAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredRepositoryAction.java
deleted file mode 100644
index 7258abd..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredRepositoryAction.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.serveraction.upgrades;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.text.MessageFormat;
-import java.util.Map;
-import java.util.Set;
-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.configuration.Configuration;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
-import org.apache.ambari.server.serveraction.ServerAction;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.RepositoryType;
-import org.apache.ambari.server.state.UpgradeContext;
-import org.apache.ambari.server.state.stack.upgrade.Direction;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.inject.Inject;
-import com.google.inject.persist.Transactional;
-
-/**
- * Action that represents updating the Desired Stack Id during the middle of a stack upgrade (typically NonRolling).
- * In a {@link org.apache.ambari.server.state.stack.upgrade.UpgradeType#EXPRESS}, the effective Stack Id is
- * actually changed half-way through calculating the Actions, and this serves to update the database to make it
- * evident to the user at which point it changed.
- */
-public class UpdateDesiredRepositoryAction extends AbstractUpgradeServerAction {
-
-  /**
-   * Logger.
-   */
-  private static final Logger LOG = LoggerFactory.getLogger(UpdateDesiredRepositoryAction.class);
-
-  /**
-   * The Ambari configuration.
-   */
-  @Inject
-  private Configuration m_configuration;
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext)
-      throws AmbariException, InterruptedException {
-
-    String clusterName = getExecutionCommand().getClusterName();
-    Cluster cluster = getClusters().getCluster(clusterName);
-    UpgradeContext upgradeContext = getUpgradeContext(cluster);
-
-    Map<String, String> roleParams = getExecutionCommand().getRoleParams();
-
-    // Make a best attempt at setting the username
-    String userName;
-    if (roleParams != null && roleParams.containsKey(ServerAction.ACTION_USER_NAME)) {
-      userName = roleParams.get(ServerAction.ACTION_USER_NAME);
-    } else {
-      userName = m_configuration.getAnonymousAuditName();
-      LOG.warn(String.format("Did not receive role parameter %s, will save configs using anonymous username %s", ServerAction.ACTION_USER_NAME, userName));
-    }
-
-    CommandReport commandReport = updateDesiredRepositoryVersion(cluster, upgradeContext, userName);
-    m_upgradeHelper.publishDesiredRepositoriesUpdates(upgradeContext);
-    return commandReport;
-  }
-
-  /**
-   * Sets the desired repository version for services participating in the
-   * upgrade.
-   *
-   * @param cluster
-   *          the cluster
-   * @param upgradeContext
-   *          the upgrade context
-   * @param userName
-   *          username performing the action
-   * @return the command report to return
-   */
-  @Transactional
-  CommandReport updateDesiredRepositoryVersion(
-      Cluster cluster, UpgradeContext upgradeContext, String userName)
-      throws AmbariException, InterruptedException {
-
-    StringBuilder out = new StringBuilder();
-    StringBuilder err = new StringBuilder();
-
-    try {
-      // the desired repository message to put in the command report - this will
-      // change based on the type of upgrade and the services participating
-      if (upgradeContext.getDirection() == Direction.UPGRADE) {
-        final String message;
-        RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getRepositoryVersion();
-
-        if (upgradeContext.getOrchestrationType() == RepositoryType.STANDARD) {
-          message = MessageFormat.format(
-              "Updating the desired repository version to {0} for all cluster services.",
-              targetRepositoryVersion.getVersion());
-        } else {
-          Set<String> servicesInUpgrade = upgradeContext.getSupportedServices();
-          message = MessageFormat.format(
-              "Updating the desired repository version to {0} for the following services: {1}",
-              targetRepositoryVersion.getVersion(), StringUtils.join(servicesInUpgrade, ','));
-        }
-
-        out.append(message).append(System.lineSeparator());
-      }
-
-      if( upgradeContext.getDirection() == Direction.DOWNGRADE ){
-        String message = "Updating the desired repository back their original values for the following services:";
-        out.append(message).append(System.lineSeparator());
-
-        Map<String, RepositoryVersionEntity> targetVersionsByService = upgradeContext.getTargetVersions();
-        for (String serviceName : targetVersionsByService.keySet()) {
-          RepositoryVersionEntity repositoryVersion = targetVersionsByService.get(serviceName);
-
-          message = String.format("  %s to %s", serviceName, repositoryVersion.getVersion());
-          out.append(message).append(System.lineSeparator());
-        }
-      }
-
-      // move repositories to the right version and create/revert configs
-      m_upgradeHelper.updateDesiredRepositoriesAndConfigs(upgradeContext);
-
-      return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", out.toString(), err.toString());
-    } catch (Exception e) {
-      StringWriter sw = new StringWriter();
-      e.printStackTrace(new PrintWriter(sw));
-      err.append(sw);
-
-      return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString());
-    }
-  }
-}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
index ef145e4..302c6bd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
@@ -49,6 +49,9 @@ import com.google.inject.Inject;
  *
  * @see org.apache.ambari.server.state.kerberos.KerberosDescriptorUpdateHelper
  */
+@Experimental(
+    feature = ExperimentalFeature.MPACK_UPGRADES,
+    comment = "Needs to move away from stacks and to service groups & mpacks")
 public class UpgradeUserKerberosDescriptor extends AbstractUpgradeServerAction {
   private static final Logger LOG = LoggerFactory.getLogger(UpgradeUserKerberosDescriptor.class);
 
@@ -97,8 +100,8 @@ public class UpgradeUserKerberosDescriptor extends AbstractUpgradeServerAction {
           feature = ExperimentalFeature.PATCH_UPGRADES,
           comment = "This needs to be correctly done per-service")
 
-      StackId originalStackId = cluster.getCurrentStackVersion();
-      StackId targetStackId = upgradeContext.getRepositoryVersion().getStackId();
+      StackId originalStackId = null;
+      StackId targetStackId = null;
 
       if (upgradeContext.getDirection() == Direction.DOWNGRADE) {
         restoreDescriptor(foreignKeys, messages, errorMessages);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
index 424798e..19d357d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
@@ -30,16 +30,17 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.ModuleComponent;
+import org.apache.ambari.server.state.Mpack;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeState;
-import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.utils.HTTPUtils;
 import org.apache.ambari.server.utils.HostAndPort;
 import org.apache.ambari.server.utils.StageUtils;
@@ -205,21 +206,13 @@ public class MasterHostResolver {
           continue;
         }
 
-        if(m_upgradeContext.getDirection() == Direction.UPGRADE){
-          RepositoryVersionEntity targetRepositoryVersion = m_upgradeContext.getRepositoryVersion();
-          if (!StringUtils.equals(targetRepositoryVersion.getVersion(), sch.getVersion())) {
-            upgradeHosts.add(hostName);
-          }
+        long serviceGroupId = sch.getServiceGroupId();
+        ServiceGroup serviceGroup = m_cluster.getServiceGroup(serviceGroupId);
+        Mpack targetMpack = m_upgradeContext.getTargetMpack(serviceGroup);
+        ModuleComponent targetModuleComponent = targetMpack.getModuleComponent(service, component);
 
-          continue;
-        }
-
-        // it's a downgrade ...
-        RepositoryVersionEntity downgradeToRepositoryVersion = m_upgradeContext.getTargetRepositoryVersion(service);
-        String downgradeToVersion = downgradeToRepositoryVersion.getVersion();
-        if (!StringUtils.equals(downgradeToVersion, sch.getVersion())) {
+        if (!StringUtils.equals(targetModuleComponent.getVersion(), sch.getVersion())) {
           upgradeHosts.add(hostName);
-          continue;
         }
       }
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Module.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Module.java
index ec7f25d..3b81f51 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Module.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Module.java
@@ -21,7 +21,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Objects;
 
-
+import com.google.common.base.MoreObjects;
 import com.google.gson.annotations.SerializedName;
 
 /* Representation of the modules section in the mpack.json*/
@@ -158,24 +158,30 @@ public class Module {
             && Objects.equals(dependencies, module.dependencies) && Objects.equals(components, module.components);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public int hashCode() {
     return Objects.hash(id, displayName, description, category, name, version, definition, dependencies, components);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public String toString() {
-    return "Module{" +
-            "id='" + id + '\'' +
-            ", displayName='" + displayName + '\'' +
-            ", description='" + description + '\'' +
-            ", category=" + category +
-            ", name='" + name + '\'' +
-            ", version='" + version + '\'' +
-            ", definition='" + definition + '\'' +
-            ", dependencies=" + dependencies +
-            ", components=" + components +
-            '}';
+    return MoreObjects.toStringHelper(this)
+    .add("id", id)
+    .add("displayName", displayName)
+    .add("description", description)
+    .add("category", category)
+    .add("name", name)
+    .add("version", version)
+    .add("definition", definition)
+    .add("dependencies", dependencies)
+    .add("components", components)
+    .toString();
   }
 
   /**
@@ -183,7 +189,10 @@ public class Module {
    */
   public void populateComponentMap() {
     componentHashMap = new HashMap<>();
-    for (ModuleComponent moduleComponent : this.getComponents()){
+    for (ModuleComponent moduleComponent : getComponents()){
+      // set reverse lookup
+      moduleComponent.setModule(this);
+
       componentHashMap.put(moduleComponent.getName(), moduleComponent);
     }
   }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ModuleComponent.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ModuleComponent.java
index 56c82af..1883eb1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ModuleComponent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ModuleComponent.java
@@ -17,6 +17,11 @@
  */
 package org.apache.ambari.server.state;
 
+import java.util.Objects;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+
+import com.google.common.base.MoreObjects;
 import com.google.gson.annotations.SerializedName;
 
 public class ModuleComponent {
@@ -32,6 +37,12 @@ public class ModuleComponent {
   @SerializedName("version")
   private String version;
 
+  /**
+   * The owning module for this module component.
+   */
+  @JsonIgnore
+  private transient Module module;
+
   public String getId() {
     return id;
   }
@@ -72,38 +83,60 @@ public class ModuleComponent {
     this.isExternal = isExternal;
   }
 
+  @JsonIgnore
+  public Module getModule() {
+    return module;
+  }
+
+  public void setModule(Module module) {
+    this.module = module;
+  }
+
   @Override
   public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
 
     ModuleComponent that = (ModuleComponent) o;
 
-    if (id != null ? !id.equals(that.id) : that.id != null) return false;
-    if (name != null ? !name.equals(that.name) : that.name != null) return false;
-    if (category != null ? !category.equals(that.category) : that.category != null) return false;
-    if (isExternal != null ? !isExternal.equals(that.isExternal) : that.isExternal != null) return false;
+    if (id != null ? !id.equals(that.id) : that.id != null) {
+      return false;
+    }
+    if (name != null ? !name.equals(that.name) : that.name != null) {
+      return false;
+    }
+    if (category != null ? !category.equals(that.category) : that.category != null) {
+      return false;
+    }
+    if (isExternal != null ? !isExternal.equals(that.isExternal) : that.isExternal != null) {
+      return false;
+    }
     return version != null ? version.equals(that.version) : that.version == null;
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public int hashCode() {
-    int result = id != null ? id.hashCode() : 0;
-    result = 31 * result + (name != null ? name.hashCode() : 0);
-    result = 31 * result + (category != null ? category.hashCode() : 0);
-    result = 31 * result + (isExternal != null ? isExternal.hashCode() : 0);
-    result = 31 * result + (version != null ? version.hashCode() : 0);
-    return result;
+    return Objects.hash(id, name, category, isExternal, version);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public String toString() {
-    return "ModuleComponent{" +
-            "id='" + id + '\'' +
-            ", name='" + name + '\'' +
-            ", category='" + category + '\'' +
-            ", isExternal=" + isExternal +
-            ", version='" + version + '\'' +
-            '}';
+    return MoreObjects.toStringHelper(this)
+    .add("id", id)
+    .add("name", name)
+    .add("category", category)
+    .add("isExternal", isExternal)
+    .add("version", version)
+    .toString();
   }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Mpack.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Mpack.java
index 8330b3c..1a23f38 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Mpack.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Mpack.java
@@ -21,11 +21,15 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 import org.apache.ambari.server.stack.RepoUtil;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang3.StringUtils;
 
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Sets;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -196,6 +200,16 @@ public class Mpack {
   }
 
   /**
+   * Gets the stack ID of this mpack, which is a combination of name and
+   * version.
+   *
+   * @return the stack ID of the mpack.
+   */
+  public StackId getStackId() {
+    return new StackId(name, version);
+  }
+
+  /**
    * Gets the module with the given name. Module names are service names.
    *
    * @param moduleName
@@ -217,9 +231,10 @@ public class Mpack {
    */
   public ModuleComponent getModuleComponent(String moduleName, String moduleComponentName) {
    Module module = moduleHashMap.get(moduleName);
-      if(module !=null){
-        return module.getModuleComponent(moduleComponentName);
-      }
+    if (module != null) {
+      return module.getModuleComponent(moduleComponentName);
+    }
+
     return null;
   }
 
@@ -264,19 +279,13 @@ public class Mpack {
 
   @Override
   public String toString() {
-    return "Mpack{" +
-            "id=" + resourceId +
-            ", registryId=" + registryId +
-            ", mpackId='" + mpackId + '\'' +
-            ", name='" + name + '\'' +
-            ", version='" + version + '\'' +
-            ", prerequisites=" + prerequisites +
-            ", modules=" + modules +
-            ", definition='" + definition + '\'' +
-            ", description='" + description + '\'' +
-            ", mpackUri='" + mpackUri + '\'' +
-            ", displayName='" + mpackUri + '\'' +
-            '}';
+    return MoreObjects.toStringHelper(this)
+        .add("id", resourceId)
+        .add("registryId", registryId)
+        .add("mpackId", mpackId)
+        .add("name", name)
+        .add("version", version)
+        .add("displayName", displayName).toString();
   }
 
   public void copyFrom(Mpack mpack) {
@@ -319,9 +328,273 @@ public class Mpack {
    */
   public void populateModuleMap() {
     moduleHashMap = new HashMap<>();
-    for(Module module : this.modules){
+    for(Module module : modules){
       module.populateComponentMap();
       moduleHashMap.put(module.getName(), module);
     }
   }
+
+  /**
+   * Gets a summary of the version changes between two mpacks. This will not
+   * look at things like mpack descriptions, URLs, etc. It only returns
+   * additions, removals, and version changes of the module components.
+   *
+   * @param other
+   *          the mpack to compare with.
+   * @return a summary of changes.
+   */
+  public MpackChangeSummary getChangeSummary(Mpack other) {
+    MpackChangeSummary summary = new MpackChangeSummary(this, other);
+    return summary;
+  }
+
+  /**
+   * Contains an aggregated summary of changes in module and component version
+   * from one mpack to another. This will only represent version changes between
+   * components (or additions and removals).
+   */
+  public static class MpackChangeSummary {
+    private Set<ModuleComponent> m_added = Sets.newLinkedHashSet();
+    private Set<ModuleComponent> m_removed = Sets.newLinkedHashSet();
+    private Set<ModuleVersionChange> m_moduleVersionChanges = Sets.newLinkedHashSet();
+    private Set<ModuleComponentVersionChange> m_componentVersionChanges = Sets.newLinkedHashSet();
+
+    private final Mpack m_source;
+    private final Mpack m_target;
+
+    /**
+     * Constructor.
+     *
+     * @param source
+     *          the source mpack to diff from.
+     * @param other
+     *          the mpack to diff against.
+     */
+    public MpackChangeSummary(Mpack source, Mpack target) {
+      m_source = source;
+      m_target = target;
+
+      for (Module module : source.getModules()) {
+        Module otherModule = target.getModule(module.getName());
+        if (null == otherModule) {
+          module.getComponents().stream().peek(moduleComponent -> removed(moduleComponent));
+
+          continue;
+        }
+
+        // no change in module version, no components changed
+        if (StringUtils.equals(module.getVersion(), otherModule.getVersion())) {
+          continue;
+        }
+
+        // module version changed
+        ModuleVersionChange moduleVersionChange = changed(module, otherModule);
+
+        for (ModuleComponent moduleComponent : module.getComponents()) {
+          ModuleComponent otherComponent = module.getModuleComponent(moduleComponent.getName());
+          if (null == otherComponent) {
+            removed(moduleComponent);
+            continue;
+          }
+
+          // module component version changed
+          if (!StringUtils.equals(moduleComponent.getVersion(), otherComponent.getVersion())) {
+            changed(moduleVersionChange, moduleComponent, otherComponent);
+          }
+        }
+      }
+
+      for (Module otherModule : target.getModules()) {
+        Module thisModule = source.getModule(otherModule.getName());
+        if (null == thisModule) {
+          otherModule.getComponents().stream().peek(moduleComponent -> added(moduleComponent));
+
+          continue;
+        }
+
+        for (ModuleComponent otherComponent : otherModule.getComponents()) {
+          ModuleComponent thisComponent = thisModule.getModuleComponent(otherComponent.getName());
+          if (null == thisComponent) {
+            added(otherComponent);
+          }
+        }
+      }
+    }
+
+    /**
+     * Gets whether there are any changes represented by this summary.
+     */
+    public boolean hasChanges() {
+      return !(m_added.isEmpty() && m_removed.isEmpty() && m_moduleVersionChanges.isEmpty());
+    }
+
+    /**
+     * A module component was added between mpacks.
+     *
+     * @param moduleComponent
+     *          the added module component.
+     */
+    public void added(ModuleComponent moduleComponent) {
+      m_added.add(moduleComponent);
+    }
+
+    /**
+     * A module was changed between mpacks.
+     *
+     * @param moduleComponent
+     *          the removed module component.
+     */
+    public ModuleVersionChange changed(Module source, Module target) {
+      ModuleVersionChange change = new ModuleVersionChange(source, target);
+      m_moduleVersionChanges.add(change);
+      return change;
+    }
+
+    /**
+     * A module component was changed between mpacks.
+     *
+     * @param moduleVersionChange
+     *          the parent module change for this component.
+     * @param source
+     *          the source component version
+     * @param target
+     *          the target component version
+     */
+    public ModuleComponentVersionChange changed(ModuleVersionChange moduleVersionChange,
+        ModuleComponent source, ModuleComponent target) {
+      ModuleComponentVersionChange change = new ModuleComponentVersionChange(source, target);
+      m_componentVersionChanges.add(change);
+
+      moduleVersionChange.m_componentChanges.add(change);
+      return change;
+    }
+
+    /**
+     * A module component had a version changed between mpacks.
+     *
+     * @param moduleComponent
+     */
+    public void removed(ModuleComponent moduleComponent) {
+      m_removed.add(moduleComponent);
+    }
+
+    /**
+     * @return the added
+     */
+    public Set<ModuleComponent> getAdded() {
+      return m_added;
+    }
+
+    /**
+     * @return the removed
+     */
+    public Set<ModuleComponent> getRemoved() {
+      return m_removed;
+    }
+
+    /**
+     * Gets all modules which have changed versions.
+     *
+     * @return the changed modules
+     */
+    public Set<ModuleVersionChange> getModuleVersionChanges() {
+      return m_moduleVersionChanges;
+    }
+
+    /**
+     * Gets all components which have changed versions.
+     *
+     * @return the changed modules.
+     */
+    public Set<ModuleComponentVersionChange> getComponentVersionChanges() {
+      return m_componentVersionChanges;
+    }
+
+    /**
+     * Gets the source mpack the diff is from.
+     *
+     * @return the source
+     */
+    public Mpack getSource() {
+      return m_source;
+    }
+
+    /**
+     * Gets the mpack which was diff'd against.
+     *
+     * @return the other
+     */
+    public Mpack getTarget() {
+      return m_target;
+    }
+
+    /**
+     * Gets whether there are version changes of module components between
+     * mpacks.
+     *
+     * @return
+     */
+    public boolean hasVersionChanges() {
+      return !m_moduleVersionChanges.isEmpty();
+    }
+  }
+
+  /**
+   * Represents a change in module versions.
+   */
+  public static class ModuleVersionChange {
+    private final Module m_source;
+    private final Module m_target;
+    private final Set<ModuleComponentVersionChange> m_componentChanges = Sets.newLinkedHashSet();
+
+    /**
+     * Constructor.
+     *
+     * @param source
+     * @param target
+     */
+    public ModuleVersionChange(Module source, Module target) {
+      m_source = source;
+      m_target = target;
+    }
+
+    public Module getSource() {
+      return m_source;
+    }
+
+    public Module getTarget() {
+      return m_target;
+    }
+
+    public Set<ModuleComponentVersionChange> getComponentChanges() {
+      return m_componentChanges;
+    }
+  }
+
+  /**
+   * Represents a change in module component versions.
+   */
+  public static class ModuleComponentVersionChange {
+    private final ModuleComponent m_source;
+    private final ModuleComponent m_target;
+
+    /**
+     * Constructor.
+     *
+     * @param source
+     * @param target
+     */
+    public ModuleComponentVersionChange(ModuleComponent source, ModuleComponent target) {
+      m_source = source;
+      m_target = target;
+    }
+
+    public ModuleComponent getSource() {
+      return m_source;
+    }
+
+    public ModuleComponent getTarget() {
+      return m_target;
+    }
+  }
 }
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
deleted file mode 100644
index da2eb06..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryType.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.state;
-
-import java.util.EnumSet;
-
-/**
- * Identifies the type of repository
- */
-public enum RepositoryType {
-
-  /**
-   * Repository should be considered to have all components for a cluster
-   * deployment.
-   */
-  STANDARD,
-
-  /**
-   * Repository may have only minimum components and is used for patching
-   * purposes.
-   */
-  PATCH,
-
-  /**
-   * Repository is used as Maintenance release, which could be several patches rolled up in one.
-   * Orchestration should treat Maintenance just as it does for Patch..
-   */
-  MAINT,
-
-  /**
-   * Repository is used to update services.
-   */
-  SERVICE;
-
-  /**
-   * The types of repositories which are revertable.
-   */
-  public static final EnumSet<RepositoryType> REVERTABLE = EnumSet.of(RepositoryType.MAINT,
-      RepositoryType.PATCH);
-
-  /**
-   * The types of repositories which can participate in an upgrade where only
-   * some services are orchestrated.
-   */
-  public static final EnumSet<RepositoryType> PARTIAL = EnumSet.of(RepositoryType.MAINT,
-      RepositoryType.PATCH, RepositoryType.SERVICE);
-
-  /**
-   * Gets whether applications of this repository are revertable after they have
-   * been finalized.
-   *
-   * @return {@code true} if the repository can be revert, {@code false}
-   *         otherwise.
-   */
-  public boolean isRevertable() {
-    switch (this) {
-      case MAINT:
-      case PATCH:
-        return true;
-      case SERVICE:
-      case STANDARD:
-        return false;
-      default:
-        return false;
-    }
-  }
-
-  /**
-   * Gets whether this repository type can be used to upgrade only a subset of
-   * services.
-   *
-   * @return {@code true} if the repository can be be applied to a subset of
-   *         isntalled services, {@code false} otherwise.
-   */
-  public boolean isPartial() {
-    return PARTIAL.contains(this);
-  }
-}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
index 04623de..447bba2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.state;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -41,6 +42,7 @@ import org.apache.ambari.server.orm.entities.StackEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.MoreObjects;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import com.google.inject.persist.Transactional;
@@ -382,4 +384,45 @@ public class ServiceGroupImpl implements ServiceGroup {
     }).collect(Collectors.toList());
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode() {
+    return Objects.hash(mpackId, serviceGroupName);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(Object object) {
+    if (null == object) {
+      return false;
+    }
+
+    if (this == object) {
+      return true;
+    }
+
+    if (object.getClass() != getClass()) {
+      return false;
+    }
+
+    ServiceGroupImpl that = (ServiceGroupImpl) object;
+
+    return Objects.equals(mpackId, that.mpackId)
+        && Objects.equals(serviceGroupName, that.serviceGroupName);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("mpackId", mpackId)
+        .add("serviceGroupName", serviceGroupName).toString();
+  }
+
 }
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 ee98f13..4482aca 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,11 +17,10 @@
  */
 package org.apache.ambari.server.state;
 
-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_PLAN_ID;
 import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_REVERT_UPGRADE_ID;
 import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_FAILURES;
 import static org.apache.ambari.server.controller.internal.UpgradeResourceProvider.UPGRADE_SKIP_MANUAL_VERIFICATION;
@@ -31,14 +30,15 @@ import static org.apache.ambari.server.controller.internal.UpgradeResourceProvid
 
 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.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
@@ -59,11 +59,17 @@ 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.UpgradeDAO;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.MpackEntity;
+import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
+import org.apache.ambari.server.orm.entities.UpgradePlanDetailEntity;
+import org.apache.ambari.server.orm.entities.UpgradePlanEntity;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
+import org.apache.ambari.server.state.Mpack.ModuleComponentVersionChange;
+import org.apache.ambari.server.state.Mpack.ModuleVersionChange;
+import org.apache.ambari.server.state.Mpack.MpackChangeSummary;
 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;
@@ -72,15 +78,14 @@ 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.LifecycleType;
-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.NotImplementedException;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Objects;
-import com.google.common.collect.Sets;
+import com.google.common.base.MoreObjects;
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.google.gson.annotations.SerializedName;
@@ -128,18 +133,6 @@ public class UpgradeContext {
   private UpgradePack m_upgradePack;
 
   /**
-   * 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 final RepositoryVersionEntity m_repositoryVersion;
-
-  /**
    * Resolves master components on hosts.
    */
   private final MasterHostResolver m_resolver;
@@ -151,16 +144,6 @@ public class UpgradeContext {
   private final List<ServiceComponentHost> m_unhealthy = new ArrayList<>();
 
   /**
-   * Mapping of service name to display name.
-   */
-  private final Map<String, String> m_serviceNames = new HashMap<>();
-
-  /**
-   * Mapping of component name to display name.
-   */
-  private final Map<String, String> m_componentNames = new HashMap<>();
-
-  /**
    * {@code true} if slave/client component failures should be automatically
    * skipped. This will only automatically skip the failure if the task is
    * skippable to begin with.
@@ -180,27 +163,10 @@ public class UpgradeContext {
   private boolean m_autoSkipManualVerification = false;
 
   /**
-   * A set of services which are included in this upgrade. This will never be
-   * empty - if all services of a cluster are included, then the cluster's
-   * current list of services is populated.
+   * A map containing each service group participating in the upgrade and the
+   * services/components participating.
    */
-  private final Set<String> m_services = new HashSet<>();
-
-  /**
-   * 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<>();
-
-  /**
-   * A mapping of service to source (from) repository. On an upgrade, this will
-   * be the current desired repository of every service. When downgrading, this
-   * will be the same for all components and will represent the value returned
-   * from {@link #getRepositoryVersion()}.
-   */
-  private final Map<String, RepositoryVersionEntity> m_sourceRepositoryMap = new HashMap<>();
+  private final Map<ServiceGroup, MpackChangeSummary> m_serviceGroups = new HashMap<>();
 
   /**
    * Used by some {@link Grouping}s to generate commands. It is exposed here
@@ -251,48 +217,11 @@ public class UpgradeContext {
   private long m_revertUpgradeId;
 
   /**
-   * Defines orchestration type.  This is not the repository type when reverting a patch.
-   */
-  private RepositoryType m_orchestration = RepositoryType.STANDARD;
-
-  /**
    * Used to lookup overridable settings like default task parallelism
    */
   @Inject
   private Configuration configuration;
 
-  /**
-   * Reading upgrade type from provided request  or if nothing were provided,
-   * from previous upgrade for downgrade direction.
-   *
-   * @param upgradeRequestMap arguments provided for current upgrade request
-   * @param upgradeEntity previous upgrade entity, should be passed only for downgrade direction
-   *
-   * @return
-   * @throws AmbariException
-   */
-  private UpgradeType calculateUpgradeType(Map<String, Object> upgradeRequestMap,
-                                           UpgradeEntity upgradeEntity) throws AmbariException{
-
-    UpgradeType upgradeType = UpgradeType.ROLLING;
-
-    String upgradeTypeProperty = (String) upgradeRequestMap.get(UPGRADE_TYPE);
-    boolean upgradeTypePassed = StringUtils.isNotBlank(upgradeTypeProperty);
-
-    if (upgradeTypePassed){
-      try {
-        upgradeType = UpgradeType.valueOf(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 if (upgradeEntity != null){
-      upgradeType = upgradeEntity.getUpgradeType();
-    }
-
-    return upgradeType;
-  }
-
   @AssistedInject
   public UpgradeContext(@Assisted Cluster cluster,
       @Assisted Map<String, Object> upgradeRequestMap, Gson gson, UpgradeHelper upgradeHelper,
@@ -321,11 +250,6 @@ public class UpgradeContext {
                 cluster.getClusterName()));
       }
 
-      if (!revertUpgrade.getOrchestration().isRevertable()) {
-        throw new AmbariException(String.format("The %s repository type is not revertable",
-            revertUpgrade.getOrchestration()));
-      }
-
       if (revertUpgrade.getDirection() != Direction.UPGRADE) {
         throw new AmbariException(
             "Only successfully completed upgrades can be reverted. Downgrades cannot be reverted.");
@@ -333,97 +257,77 @@ public class UpgradeContext {
 
       if (!revertableUpgrade.getId().equals(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",
+            "The only upgrade which is currently allowed to be reverted for cluster %s is upgrade ID %s which was an upgrade to the following mpacks: %s",
             cluster.getClusterName(), revertableUpgrade.getId(),
-            revertableUpgrade.getRepositoryVersion().getVersion()));
+            revertableUpgrade.getTargetMpackStacks()));
       }
 
       m_type = calculateUpgradeType(upgradeRequestMap, revertUpgrade);
 
       // !!! build all service-specific reversions
-      Set<RepositoryVersionEntity> priors = new HashSet<>();
-      Map<String, Service> clusterServices = cluster.getServicesByName();
       for (UpgradeHistoryEntity history : revertUpgrade.getHistory()) {
-        String serviceName = history.getServiceName();
-        String componentName = history.getComponentName();
+        ServiceGroupEntity serviceGroupEntity = history.getServiceGroupEntity();
 
-        priors.add(history.getFromReposistoryVersion());
+        // reverse these on the revert
+        MpackEntity sourceMpackEntity = history.getTargetMpackEntity();
+        MpackEntity targetMpackEntity = history.getSourceMpackEntity();
 
-        // if the service is no longer installed, do nothing
-        if (!clusterServices.containsKey(serviceName)) {
-          LOG.warn("{}/{} will not be reverted since it is no longer installed in the cluster",
-              serviceName, componentName);
+        ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupEntity.getServiceGroupId());
+
+        // if the service group is no longer installed, do nothing
+        if (null == serviceGroup) {
+          LOG.warn(
+              "The service group {} will not be reverted since it is no longer installed in the cluster",
+              serviceGroupEntity.getServiceGroupName());
 
           continue;
         }
 
-        m_services.add(serviceName);
-        m_sourceRepositoryMap.put(serviceName, history.getTargetRepositoryVersion());
-        m_targetRepositoryMap.put(serviceName, history.getFromReposistoryVersion());
-      }
-
-      if (priors.size() != 1) {
-        String message = String.format("Upgrade from %s could not be reverted as there is no single "
-            + " repository across services.", revertUpgrade.getRepositoryVersion().getVersion());
-
-        throw new AmbariException(message);
+        Mpack sourceMpack = m_metaInfo.getMpack(sourceMpackEntity.getId());
+        Mpack targetMpack = m_metaInfo.getMpack(targetMpackEntity.getId());
+        MpackChangeSummary summary = sourceMpack.getChangeSummary(targetMpack);
+        m_serviceGroups.put(serviceGroup, summary);
       }
 
-      m_repositoryVersion = priors.iterator().next();
-
-      // !!! the version is used later in validators
-      upgradeRequestMap.put(UPGRADE_REPO_VERSION_ID, m_repositoryVersion.getId().toString());
       // !!! use the same upgrade pack that was used in the upgrade being reverted
       upgradeRequestMap.put(UPGRADE_PACK, revertUpgrade.getUpgradePackage());
 
       // !!! direction can ONLY be an downgrade on revert
       m_direction = Direction.DOWNGRADE;
-      m_orchestration = revertUpgrade.getOrchestration();
     } else {
-
-      // determine direction
-      String directionProperty = (String) upgradeRequestMap.get(UPGRADE_DIRECTION);
-      if (StringUtils.isEmpty(directionProperty)) {
-        throw new AmbariException(String.format("%s is required", UPGRADE_DIRECTION));
-      }
-
-      m_direction = Direction.valueOf(directionProperty);
+      UpgradePlanEntity upgradePlan = null;
+      m_direction = upgradePlan.getDirection();
 
       // depending on the direction, we must either have a target repository or an upgrade we are downgrading from
       switch(m_direction){
         case UPGRADE:{
-          String repositoryVersionId = (String) upgradeRequestMap.get(UPGRADE_REPO_VERSION_ID);
-          if (null == repositoryVersionId) {
-            throw new AmbariException(
-                String.format("The property %s is required when the upgrade direction is %s",
-                    UPGRADE_REPO_VERSION_ID, m_direction));
-          }
-
           m_type = calculateUpgradeType(upgradeRequestMap, null);
 
-          // depending on the repository, add services
-          m_repositoryVersion = null;
-          m_orchestration = m_repositoryVersion.getType();
-
-          // add all of the services participating in the upgrade
-          m_services.addAll(getServicesForUpgrade(cluster, m_repositoryVersion));
+          List<UpgradePlanDetailEntity> details = upgradePlan.getDetails();
+          for (UpgradePlanDetailEntity detail : details) {
+            long serviceGroupId = detail.getServiceGroupId();
+            long targetMpackId = detail.getMpackTargetId();
+            ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupId);
+            long sourceMpackId = serviceGroup.getMpackId();
+
+            Mpack sourceMpack = m_metaInfo.getMpack(sourceMpackId);
+            Mpack targetMpack = m_metaInfo.getMpack(targetMpackId);
+            MpackChangeSummary summary = sourceMpack.getChangeSummary(targetMpack);
+            if (!summary.hasVersionChanges()) {
+              continue;
+            }
+
+            m_serviceGroups.put(serviceGroup, summary);
+          }
           break;
         }
         case DOWNGRADE:{
+          @Experimental(feature = ExperimentalFeature.MPACK_UPGRADES, comment = "Populate from prior upgrade")
           UpgradeEntity upgrade = m_upgradeDAO.findLastUpgradeForCluster(
               cluster.getClusterId(), Direction.UPGRADE);
 
-          m_repositoryVersion = upgrade.getRepositoryVersion();
-          m_orchestration = upgrade.getOrchestration();
           m_type = calculateUpgradeType(upgradeRequestMap, upgrade);
-
-          // populate the repository maps for all services in the upgrade
-          for (UpgradeHistoryEntity history : upgrade.getHistory()) {
-            m_services.add(history.getServiceName());
-            m_sourceRepositoryMap.put(history.getServiceName(), m_repositoryVersion);
-            m_targetRepositoryMap.put(history.getServiceName(), history.getFromReposistoryVersion());
-          }
-
+          populateParticipatingServiceGroups(cluster, m_serviceGroups, upgrade, true);
           break;
         }
         default:
@@ -432,19 +336,13 @@ public class UpgradeContext {
       }
     }
 
-
     /**
      * 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.
      */
+    @Experimental(feature = ExperimentalFeature.MPACK_UPGRADES, comment = "No longer using single packs")
     String preferredUpgradePackName = (String) upgradeRequestMap.get(UPGRADE_PACK);
-
-    @Experimental(feature= ExperimentalFeature.REPO_VERSION_REMOVAL)
-    RepositoryVersionEntity upgradeFromRepositoryVersion = m_repositoryVersion;
-
-    m_upgradePack = m_upgradeHelper.suggestUpgradePack(m_cluster.getClusterName(),
-        upgradeFromRepositoryVersion.getStackId(), m_repositoryVersion.getStackId(), m_direction,
-        m_type, preferredUpgradePackName);
+    m_upgradePack = null;
 
     // the validator will throw an exception if the upgrade request is not valid
     UpgradeRequestValidator upgradeRequestValidator = buildValidator(m_type);
@@ -492,52 +390,27 @@ public class UpgradeContext {
    */
   @AssistedInject
   public UpgradeContext(@Assisted Cluster cluster, @Assisted UpgradeEntity upgradeEntity,
-      AmbariMetaInfo ambariMetaInfo, ConfigHelper configHelper) {
+      AmbariMetaInfo ambariMetaInfo, ConfigHelper configHelper) throws AmbariException {
     m_metaInfo = ambariMetaInfo;
 
     m_cluster = cluster;
     m_type = upgradeEntity.getUpgradeType();
     m_direction = upgradeEntity.getDirection();
-    m_repositoryVersion = upgradeEntity.getRepositoryVersion();
 
     m_autoSkipComponentFailures = upgradeEntity.isComponentFailureAutoSkipped();
     m_autoSkipServiceCheckFailures = upgradeEntity.isServiceCheckFailureAutoSkipped();
 
-    List<UpgradeHistoryEntity> allHistory = upgradeEntity.getHistory();
-    for (UpgradeHistoryEntity history : allHistory) {
-      String serviceName = history.getServiceName();
-      RepositoryVersionEntity sourceRepositoryVersion = history.getFromReposistoryVersion();
-      RepositoryVersionEntity targetRepositoryVersion = history.getTargetRepositoryVersion();
-      m_sourceRepositoryMap.put(serviceName, sourceRepositoryVersion);
-      m_targetRepositoryMap.put(serviceName, targetRepositoryVersion);
-      m_services.add(serviceName);
-    }
+    populateParticipatingServiceGroups(cluster, m_serviceGroups, upgradeEntity, false);
 
-    @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES, comment = "This is wrong")
+    @Experimental(
+        feature = ExperimentalFeature.MPACK_UPGRADES,
+        comment = "We need a way to get the upgrade packs given multiple mpacks")
     String upgradePackage = upgradeEntity.getUpgradePackage();
-    StackId stackId = m_repositoryVersion.getStackId();
-    Map<String, UpgradePack> packs = m_metaInfo.getUpgradePacks(stackId.getStackName(), stackId.getStackVersion());
+    Map<String, UpgradePack> packs = m_metaInfo.getUpgradePacks(null, null);
     m_upgradePack = packs.get(upgradePackage);
 
     m_resolver = new MasterHostResolver(m_cluster, configHelper, this);
-    m_orchestration = upgradeEntity.getOrchestration();
-
-    m_isRevert = upgradeEntity.getOrchestration().isRevertable()
-        && upgradeEntity.getDirection() == Direction.DOWNGRADE;
-  }
-
-  /**
-   * Getting stackId from the set of versions. Is is possible until we upgrading components on the same stack.
-   *
-   * Note: Function should be modified for cross-stack upgrade.
-   *
-   * @param version {@link Set} of services repository versions
-   * @return
-   * {@link StackId} based on provided versions
-   */
-  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES, comment="This is wrong")
-  public StackId getStackIdFromVersions(Map<String, RepositoryVersionEntity> version) {
-    return version.values().iterator().next().getStackId();
+    m_isRevert = upgradeEntity.isRevert();
   }
 
   /**
@@ -569,97 +442,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Gets the version that components are being considered to be "coming from".
-   * <p/>
-   * With a {@link Direction#UPGRADE}, this value represent the services'
-   * desired repository. However, {@link Direction#DOWNGRADE} will use the same
-   * value for all services which is the version that the downgrade is coming
-   * from.
-   *
-   * @return the source version for the upgrade
-   */
-  public Map<String, RepositoryVersionEntity> getSourceVersions() {
-    return new HashMap<>(m_sourceRepositoryMap);
-  }
-
-  /**
-   * Gets the version that service is being considered to be "coming from".
-   * <p/>
-   * With a {@link Direction#UPGRADE}, this value represent the services'
-   * desired repository. However, {@link Direction#DOWNGRADE} will use the same
-   * value for all services which is the version that the downgrade is coming
-   * from.
-   *
-   * @return the source repository for the upgrade
-   */
-  public RepositoryVersionEntity getSourceRepositoryVersion(String serviceName) {
-    return m_sourceRepositoryMap.get(serviceName);
-  }
-
-  /**
-   * Gets the version that service is being considered to be "coming from".
-   * <p/>
-   * With a {@link Direction#UPGRADE}, this value represent the services'
-   * desired repository. However, {@link Direction#DOWNGRADE} will use the same
-   * value for all services which is the version that the downgrade is coming
-   * from.
-   *
-   * @return the source repository for the upgrade
-   * @see #getSourceRepositoryVersion(String)
-   */
-  public String getSourceVersion(String serviceName) {
-    RepositoryVersionEntity serviceSourceVersion = m_sourceRepositoryMap.get(serviceName);
-    return serviceSourceVersion.getVersion();
-  }
-
-  /**
-   * 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 targeting 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
-   * @see #getTargetRepositoryVersion(String)
-   */
-  public String getTargetVersion(String serviceName) {
-    RepositoryVersionEntity serviceTargetVersion = m_targetRepositoryMap.get(serviceName);
-    return serviceTargetVersion.getVersion();
-  }
-
-  /**
    * @return the direction of the upgrade
    */
   public Direction getDirection() {
@@ -695,64 +477,6 @@ public class UpgradeContext {
   }
 
   /**
-   * 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. <p/>
-   * 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 getRepositoryVersion() {
-    return m_repositoryVersion;
-  }
-
-  /**
-   * @return the service display name, or the service name if not set
-   */
-  public String getServiceDisplay(String service) {
-    if (m_serviceNames.containsKey(service)) {
-      return m_serviceNames.get(service);
-    }
-
-    return service;
-  }
-
-  /**
-   * @return the component display name, or the component name if not set
-   */
-  public String getComponentDisplay(String service, String component) {
-    String key = service + ":" + component;
-    if (m_componentNames.containsKey(key)) {
-      return m_componentNames.get(key);
-    }
-
-    return component;
-  }
-
-  /**
-   * @param service     the service name
-   * @param displayName the display name for the service
-   */
-  public void setServiceDisplay(String service, String displayName) {
-    m_serviceNames.put(service, (displayName == null) ? service : displayName);
-  }
-
-  /**
-   * @param service     the service name that owns the component
-   * @param component   the component name
-   * @param displayName the display name for the component
-   */
-  public void setComponentDisplay(String service, String component, String displayName) {
-    String key = service + ":" + component;
-    m_componentNames.put(key, displayName);
-  }
-
-  /**
    * Gets whether skippable components that failed are automatically skipped.
    *
    * @return the skipComponentFailures
@@ -781,49 +505,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Gets the services participating in the upgrade.
-   *
-   * @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_services);
-  }
-
-  /**
-   * 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) {
-    return m_services.contains(serviceName);
-  }
-
-  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-  public boolean isScoped(UpgradeScope scope) {
-    if (scope == UpgradeScope.ANY) {
-      return true;
-    }
-
-    switch (m_orchestration) {
-      case PATCH:
-      case SERVICE:
-      case MAINT:
-        return scope == UpgradeScope.PARTIAL;
-      case STANDARD:
-        return scope == UpgradeScope.COMPLETE;
-      default:
-        break;
-    }
-
-    return false;
-  }
-
-  /**
    * Gets the injected instance of a {@link RoleGraphFactory}.
    *
    * @return a {@link RoleGraphFactory} instance (never {@code null}).
@@ -842,18 +523,6 @@ public class UpgradeContext {
   }
 
   /**
-   * Gets the repository type to determine if this upgrade is a complete upgrade
-   * or a service/patch.  This value is not always the same as the repository version.  In
-   * the case of a revert of a patch, the target repository may be of type STANDARD, but orchestration
-   * must be "like a patch".
-   *
-   * @return the orchestration type.
-   */
-  public RepositoryType getOrchestrationType() {
-    return m_orchestration;
-  }
-
-  /**
    * Gets a map initialized with parameters required for upgrades to work. The
    * following properties are already set:
    * <ul>
@@ -895,10 +564,9 @@ public class UpgradeContext {
    */
   @Override
   public String toString() {
-    return Objects.toStringHelper(this)
+    return MoreObjects.toStringHelper(this)
         .add("direction", m_direction)
-        .add("type", m_type)
-        .add("target", m_repositoryVersion).toString();
+        .add("type", m_type).toString();
   }
 
   /**
@@ -929,6 +597,18 @@ public class UpgradeContext {
   }
 
   /**
+   * Gets whether this upgrade is revertable.
+   *
+   * @return
+   */
+  @Experimental(
+      feature = ExperimentalFeature.MPACK_UPGRADES,
+      comment = "This must be stored in an upgrade pack or calculated from the versions")
+  public boolean isRevertable() {
+    throw new NotImplementedException();
+  }
+
+  /**
    * @return default value of number of tasks to run in parallel during upgrades
    */
   public int getDefaultMaxDegreeOfParallelism() {
@@ -943,59 +623,232 @@ public class UpgradeContext {
   public UpgradeSummary getUpgradeSummary() {
     UpgradeSummary summary = new UpgradeSummary();
     summary.direction = m_direction;
-    summary.type = m_type;
-    summary.orchestration = m_orchestration;
     summary.isRevert = m_isRevert;
+    summary.serviceGroups = new HashMap<>();
+
+    for (ServiceGroup serviceGroup : m_serviceGroups.keySet()) {
+      MpackChangeSummary changeSummary = m_serviceGroups.get(serviceGroup);
+
+      UpgradeServiceGroupSummary serviceGroupSummary = new UpgradeServiceGroupSummary();
+      serviceGroupSummary.type = m_type;
+      serviceGroupSummary.sourceMpackId = changeSummary.getSource().getResourceId();
+      serviceGroupSummary.sourceStack = changeSummary.getSource().getStackId().getStackId();
+      serviceGroupSummary.targetMpackId = changeSummary.getTarget().getRegistryId();
+      serviceGroupSummary.targetStack = changeSummary.getTarget().getStackId().getStackId();
+      serviceGroupSummary.services = new LinkedHashMap<>();
+
+      summary.serviceGroups.put(serviceGroup.getServiceGroupName(), serviceGroupSummary);
+
+      for( ModuleVersionChange moduleVersionChange : changeSummary.getModuleVersionChanges() ) {
+        UpgradeServiceSummary upgradeServiceSummary = new UpgradeServiceSummary();
+        upgradeServiceSummary.sourceVersion = moduleVersionChange.getSource().getVersion();
+        upgradeServiceSummary.targetVersion = moduleVersionChange.getTarget().getVersion();
+        upgradeServiceSummary.components = new LinkedHashMap<>();
+        serviceGroupSummary.services.put(moduleVersionChange.getSource().getName(), upgradeServiceSummary);
+
+        for( ModuleComponentVersionChange componentVersionChange : moduleVersionChange.getComponentChanges() ) {
+          UpgradeComponentSummary componentSummary = new UpgradeComponentSummary();
+          componentSummary.sourceVersion = componentVersionChange.getSource().getVersion();
+          componentSummary.targetVersion = componentVersionChange.getTarget().getVersion();
+
+          upgradeServiceSummary.components.put(componentVersionChange.getSource().getName(), componentSummary);
+        }
+      }
+    }
 
-    summary.services = new HashMap<>();
+    return summary;
+  }
 
-    for (String serviceName : m_services) {
-      RepositoryVersionEntity sourceRepositoryVersion = m_sourceRepositoryMap.get(serviceName);
-      RepositoryVersionEntity targetRepositoryVersion = m_targetRepositoryMap.get(serviceName);
-      if (null == sourceRepositoryVersion || null == targetRepositoryVersion) {
-        LOG.warn("Unable to get the source/target repositories for {} for the upgrade summary",
-            serviceName);
-        continue;
-      }
+  /**
+   * Gets the service groups participating in the upgrade, mapped to their
+   * respective {@link MpackChangeSummary}s.
+   *
+   * @return the service groups in the upgrade.
+   */
+  public Map<ServiceGroup, MpackChangeSummary> getServiceGroups() {
+    return m_serviceGroups;
+  }
 
-      UpgradeServiceSummary serviceSummary = new UpgradeServiceSummary();
-      serviceSummary.sourceRepositoryId = sourceRepositoryVersion.getId();
-      serviceSummary.sourceStackId = sourceRepositoryVersion.getStackId().getStackId();
-      serviceSummary.sourceVersion = sourceRepositoryVersion.getVersion();
+  /**
+   * Gets the target management packs for this upgrade.
+   *
+   * @return the target mpacks for all service groups participating.
+   */
+  public Set<Mpack> getTargetMpacks() {
+    return m_serviceGroups.values().stream().map(serviceGroup -> serviceGroup.getTarget()).collect(
+        Collectors.toSet());
+  }
 
-      serviceSummary.targetRepositoryId = targetRepositoryVersion.getId();
-      serviceSummary.targetStackId = targetRepositoryVersion.getStackId().getStackId();
-      serviceSummary.targetVersion = targetRepositoryVersion.getVersion();
+  /**
+   * Gets the source mpack for the specified service group in this upgrade.
+   *
+   * @param serviceGroup
+   *          the service group
+   * @return the source mpack, or {@code null} if the service group is not
+   *         participating.
+   */
+  public Mpack getSourceMpack(ServiceGroup serviceGroup) {
+    Mpack source = null;
+    MpackChangeSummary changeSummary = m_serviceGroups.get(serviceGroup);
+    if (null != changeSummary) {
+      source = changeSummary.getSource();
+    }
 
-      summary.services.put(serviceName, serviceSummary);
+    return source;
+  }
+
+  /**
+   * Gets the target mpack for the specified service group in this upgrade.
+   *
+   * @param serviceGroup
+   *          the service group
+   * @return the target mpack, or {@code null} if the service group is not
+   *         participating.
+   */
+  public Mpack getTargetMpack(ServiceGroup serviceGroup) {
+    Mpack target = null;
+    MpackChangeSummary changeSummary = m_serviceGroups.get(serviceGroup);
+    if (null != changeSummary) {
+      target = changeSummary.getTarget();
     }
 
-    return summary;
+    return target;
+  }
+
+  /**
+   * Gets whether the service is supported in this upgrade.
+   *
+   * @param serviceName
+   * @return
+   */
+  @Experimental(feature=ExperimentalFeature.MPACK_UPGRADES, comment = "Needs implementation and thought")
+  public boolean isSupportedInUpgrade(String serviceName) {
+    return false;
+  }
+
+  /**
+   * Gets the display name for a given service.
+   *
+   * @param mpack
+   *          the mpack which owns the service.
+   * @param serviceName
+   *          the service name.
+   * @return the service display name.
+   */
+  public String getDisplayName(Mpack mpack, String serviceName) {
+    Module module = mpack.getModule(serviceName);
+    if (null == module) {
+      return serviceName;
+    }
+
+    return module.getDisplayName();
+
+  }
+
+  /**
+   * Gets the display name for a given component.
+   *
+   * @param mpack
+   *          the mpack which owns the service.
+   * @param serviceName
+   *          the component's service.
+   * @param componentName
+   *          the component name.
+   * @return the component display name.
+   */
+  public String getDisplayName(Mpack mpack, String serviceName, String componentName) {
+    ModuleComponent moduleComponent = mpack.getModuleComponent(serviceName, componentName);
+    if (null == moduleComponent) {
+      return componentName;
+    }
+
+    return moduleComponent.getName();
+  }
+
+  /**
+   * Gets a displayable summary of the service groups and their upgrade
+   * information.
+   *
+   * @return a displayable summary of the upgrade at the service group level.
+   */
+  public String getServiceGroupDisplayableSummary() {
+    StringBuilder buffer = new StringBuilder();
+    for (ServiceGroup serviceGroup : m_serviceGroups.keySet()) {
+      MpackChangeSummary changeSummary = m_serviceGroups.get(serviceGroup);
+      Mpack source = changeSummary.getSource();
+      Mpack target = changeSummary.getTarget();
+
+      buffer.append(serviceGroup.getServiceGroupName()).append(": ").append(
+          source.getStackId()).append("->").append(target.getStackId()).append(
+              System.lineSeparator());
+    }
+
+    return buffer.toString();
+  }
+
+  /**
+   * Reading upgrade type from provided request or if nothing were provided,
+   * from previous upgrade for downgrade direction.
+   *
+   * @param upgradeRequestMap
+   *          arguments provided for current upgrade request
+   * @param upgradeEntity
+   *          previous upgrade entity, should be passed only for downgrade
+   *          direction
+   *
+   * @return
+   * @throws AmbariException
+   */
+  private UpgradeType calculateUpgradeType(Map<String, Object> upgradeRequestMap,
+                                           UpgradeEntity upgradeEntity) throws AmbariException{
+
+    UpgradeType upgradeType = UpgradeType.ROLLING;
+
+    String upgradeTypeProperty = (String) upgradeRequestMap.get(UPGRADE_TYPE);
+    boolean upgradeTypePassed = StringUtils.isNotBlank(upgradeTypeProperty);
+
+    if (upgradeTypePassed){
+      try {
+        upgradeType = UpgradeType.valueOf(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 if (upgradeEntity != null){
+      upgradeType = upgradeEntity.getUpgradeType();
+    }
+
+    return upgradeType;
   }
 
   /**
-   * Gets the set of services which will participate in the upgrade. The
-   * services available in the repository are comapred against those installed
-   * in the cluster to arrive at the final subset.
-   * <p/>
-   * In some cases, such as with a {@link RepositoryType#MAINT} repository, the
-   * subset can be further trimmed by determing that an installed services is
-   * already at a high enough version and doesn't need to be upgraded.
-   * <p/>
-   * This method will also populate the source ({@link #m_sourceRepositoryMap})
-   * and target ({@link #m_targetRepositoryMap}) repository maps.
+   * Populate the participating service groups and their respective mpack
+   * summary differences. This is only for an upgrade which has already been
+   * created and persisted.
    *
    * @param cluster
-   *          the cluster (not {@code null}).
-   * @param repositoryVersion
-   *          the repository to use for the upgrade (not {@code null}).
-   * @return the set of services which will participate in the upgrade.
+   * @param serviceGroups
+   * @param upgrade
+   * @param reverse
    * @throws AmbariException
    */
-  private Set<String> getServicesForUpgrade(Cluster cluster,
-      RepositoryVersionEntity repositoryVersion) throws AmbariException {
+  private void populateParticipatingServiceGroups(Cluster cluster,
+      Map<ServiceGroup, MpackChangeSummary> serviceGroups, UpgradeEntity upgrade,
+      boolean reverse) throws AmbariException {
+
+    for (UpgradeHistoryEntity history : upgrade.getHistory()) {
+      ServiceGroupEntity serviceGroupEntity = history.getServiceGroupEntity();
+      ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupEntity.getServiceGroupId());
 
-    return Sets.newHashSet();
+      // reverse these on the downgrade
+      MpackEntity sourceMpackEntity = reverse ? history.getTargetMpackEntity() : history.getSourceMpackEntity();
+      MpackEntity targetMpackEntity = reverse ? history.getSourceMpackEntity() : history.getTargetMpackEntity();
+
+      Mpack sourceMpack = m_metaInfo.getMpack(sourceMpackEntity.getId());
+      Mpack targetMpack = m_metaInfo.getMpack(targetMpackEntity.getId());
+      MpackChangeSummary summary = sourceMpack.getChangeSummary(targetMpack);
+      serviceGroups.put(serviceGroup, summary);
+    }
   }
 
   /**
@@ -1100,10 +953,10 @@ public class UpgradeContext {
         UpgradePack upgradePack, Map<String, Object> requestMap) throws AmbariException {
 
       if (direction == Direction.UPGRADE) {
-        String repositoryVersionId = (String) requestMap.get(UPGRADE_REPO_VERSION_ID);
-        if (StringUtils.isBlank(repositoryVersionId)) {
+        String upgradePlanId = (String) requestMap.get(UPGRADE_PLAN_ID);
+        if (StringUtils.isBlank(upgradePlanId)) {
           throw new AmbariException(
-              String.format("%s is required for upgrades", UPGRADE_REPO_VERSION_ID));
+              String.format("%s is required for upgrades", UPGRADE_PLAN_ID));
         }
       }
     }
@@ -1121,7 +974,7 @@ public class UpgradeContext {
     void check(Cluster cluster, Direction direction, UpgradeType type, UpgradePack upgradePack,
         Map<String, Object> requestMap) throws AmbariException {
 
-      String repositoryVersionId = (String) requestMap.get(UPGRADE_REPO_VERSION_ID);
+      String upgradePlanId = (String) requestMap.get(UPGRADE_PLAN_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;
@@ -1146,7 +999,7 @@ public class UpgradeContext {
 
       Predicate preUpgradeCheckPredicate = new PredicateBuilder().property(
           PreUpgradeCheckResourceProvider.UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).equals(cluster.getClusterName()).and().property(
-          PreUpgradeCheckResourceProvider.UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID).equals(repositoryVersionId).and().property(
+          PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PLAN_ID).equals(upgradePlanId).and().property(
           PreUpgradeCheckResourceProvider.UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID).equals(m_isRevert).and().property(
           PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID).equals(type).and().property(
           PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID).equals(preferredUpgradePack).toPredicate();
@@ -1314,36 +1167,68 @@ public class UpgradeContext {
     @SerializedName("direction")
     public Direction direction;
 
+    @SerializedName("isRevert")
+    public boolean isRevert = false;
+
+    /**
+     * Mapping of service group name to the service group in the upgrade.
+     */
+    @SerializedName("serviceGroups")
+    public Map<String, UpgradeServiceGroupSummary> serviceGroups;
+  }
+
+  /**
+   * The {@link UpgradeServiceGroupSummary} class is used as a way to
+   * encapsulate the service group components and upgrade type participating in
+   * the upgrade.
+   */
+  public static class UpgradeServiceGroupSummary {
     @SerializedName("type")
     public UpgradeType type;
 
-    @SerializedName("orchestration")
-    public RepositoryType orchestration;
+    @SerializedName("sourceMpackId")
+    public long sourceMpackId;
 
-    @SerializedName("isRevert")
-    public boolean isRevert = false;
+    @SerializedName("targetMpackId")
+    public long targetMpackId;
+
+    @SerializedName("sourceStack")
+    public String sourceStack;
+
+    @SerializedName("targetStack")
+    public String targetStack;
 
+    /**
+     * A mapping of service name to service summary information for services
+     * participating in the upgrade for this service group.
+     */
     @SerializedName("services")
     public Map<String, UpgradeServiceSummary> services;
   }
 
   /**
    * The {@link UpgradeServiceSummary} class is used as a way to encapsulate the
-   * service source and target versions during an upgrade.
+   * service component upgrade information during an upgrade.
    */
   public static class UpgradeServiceSummary {
-    @SerializedName("sourceRepositoryId")
-    public long sourceRepositoryId;
-
-    @SerializedName("targetRepositoryId")
-    public long targetRepositoryId;
+    @SerializedName("sourceVersion")
+    public String sourceVersion;
 
-    @SerializedName("sourceStackId")
-    public String sourceStackId;
+    @SerializedName("targetVersion")
+    public String targetVersion;
 
-    @SerializedName("targetStackId")
-    public String targetStackId;
+    /**
+     * Mapping of component name its com
+     */
+    @SerializedName("components")
+    public Map<String, UpgradeComponentSummary> components;
+  }
 
+  /**
+   * The {@link UpgradeComponentSummary} class is used as a way to encapsulate
+   * the component source and target versions during an upgrade.
+   */
+  public static class UpgradeComponentSummary {
     @SerializedName("sourceVersion")
     public String sourceVersion;
 
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 6f82357..89cadbb 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
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
@@ -53,13 +54,14 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-import org.apache.ambari.server.events.ClusterComponentsRepoChangedEvent;
+import org.apache.ambari.server.events.ServiceGroupMpackChangedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.metadata.ClusterMetadataGenerator;
 import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
+import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
+import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.stack.UpgradePack;
@@ -224,6 +226,12 @@ public class UpgradeHelper {
   private AmbariEventPublisher ambariEventPublisher;
 
   /**
+   * Used for getting stacks to update service groups.
+   */
+  @Inject
+  private StackDAO m_stackDAO;
+
+  /**
    * Get right Upgrade Pack, depends on stack, direction and upgrade type
    * information
    *
@@ -321,11 +329,6 @@ public class UpgradeHelper {
     UpgradeGroupHolder previousGroupHolder = null;
     for (Grouping group : upgradePack.getGroups(LifecycleType.UPGRADE, context.getDirection())) {
 
-      // !!! grouping is not scoped to context
-      if (!context.isScoped(group.scope)) {
-        continue;
-      }
-
       // if there is a condition on the group, evaluate it and skip scheduling
       // of this group if the condition has not been satisfied
       if (null != group.condition && !group.condition.isSatisfied(context)) {
@@ -376,7 +379,7 @@ public class UpgradeHelper {
       // !!! cluster and service checks are empty here
       for (UpgradePack.OrderService service : services) {
 
-        if (!context.isServiceSupported(service.serviceName)) {
+        if (!context.isSupportedInUpgrade(service.serviceName)) {
           continue;
         }
 
@@ -446,8 +449,6 @@ public class UpgradeHelper {
             continue;
           }
 
-          setDisplayNames(context, service.serviceName, component);
-
           // Special case for NAMENODE when there are multiple
           if (service.serviceName.equalsIgnoreCase("HDFS") && component.equalsIgnoreCase("NAMENODE")) {
 
@@ -642,6 +643,9 @@ public class UpgradeHelper {
    * @param component the component name if required
    * @return the source string with tokens replaced, if any are found
    */
+  @Experimental(
+      feature = ExperimentalFeature.MPACK_UPGRADES,
+      comment = "How to replace singular stack version with correct mpack version")
   private String tokenReplace(UpgradeContext ctx, String source, String service, String component) {
     Cluster cluster = ctx.getCluster();
     MasterHostResolver mhr = ctx.getResolver();
@@ -681,7 +685,8 @@ public class UpgradeHelper {
           break;
         }
         case VERSION:
-          value = ctx.getRepositoryVersion().getVersion();
+          value = ctx.getTargetMpacks().stream().map(mpack -> mpack.getVersion()).collect(
+              Collectors.joining(","));
           break;
         case DIRECTION_VERB:
         case DIRECTION_VERB_PROPER:
@@ -810,33 +815,11 @@ public class UpgradeHelper {
   }
 
   /**
-   * Helper to set service and component display names on the context
-   * @param context   the context to update
-   * @param serviceName   the service name
-   * @param component the component name
-   */
-  private void setDisplayNames(UpgradeContext context, String serviceName, String component) {
-    Cluster c = context.getCluster();
-
-    try {
-      Service service = c.getService(serviceName);
-      ServiceInfo serviceInfo = m_ambariMetaInfoProvider.get().getService(service);
-      context.setServiceDisplay(serviceName, serviceInfo.getDisplayName());
-
-      ComponentInfo compInfo = serviceInfo.getComponentByName(component);
-      context.setComponentDisplay(serviceName, component, compInfo.getDisplayName());
-
-    } catch (AmbariException e) {
-      LOG.debug("Could not get service detail", e);
-    }
-  }
-
-  /**
-   * Updates the various repositories and configurations for services
+   * Updates the various mpack associations and configurations for services
    * participating in the upgrade or downgrade. The following actions are
    * performed in order:
    * <ul>
-   * <li>The desired repository for every service and component is changed<
+   * <li>The desired mpack for every service group is changed.
    * <li>The {@link UpgradeState} of every component host is moved to either
    * {@link UpgradeState#IN_PROGRESS} or {@link UpgradeState#NONE}.
    * <li>In the case of an upgrade, new configurations and service
@@ -851,22 +834,21 @@ public class UpgradeHelper {
    */
   @Transactional
   @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-  public void updateDesiredRepositoriesAndConfigs(UpgradeContext upgradeContext)
+  public void updateDesiredMpacksAndConfigs(UpgradeContext upgradeContext)
       throws AmbariException {
-    setDesiredRepositories(upgradeContext);
+    setDesiredMpacks(upgradeContext);
     processConfigurationsIfRequired(upgradeContext);
   }
 
-  public void publishDesiredRepositoriesUpdates(UpgradeContext upgradeContext) throws AmbariException {
+  public void publishServiceGroupMpackChangeUpdate(UpgradeContext upgradeContext) throws AmbariException {
     Cluster cluster = upgradeContext.getCluster();
-    ambariEventPublisher.publish(new ClusterComponentsRepoChangedEvent(cluster.getClusterId()));
+    ambariEventPublisher.publish(new ServiceGroupMpackChangedEvent(cluster.getClusterId()));
   }
 
   /**
    * Transitions all affected components to {@link UpgradeState#IN_PROGRESS}.
    * Transition is performed only for components that advertise their version.
-   * Additionally sets the service component desired version to the specified
-   * argument.
+   * Additionally sets the service group mpack association to the desired vaue.
    * <p/>
    * Because this iterates over all of the components on every host and updates
    * the upgrade state individually, we wrap this method inside of a transaction
@@ -876,51 +858,47 @@ public class UpgradeHelper {
    *          the upgrade context (not {@code null}).
    */
   @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-  private void setDesiredRepositories(UpgradeContext upgradeContext) throws AmbariException {
-    Cluster cluster = upgradeContext.getCluster();
-    Set<String> services = upgradeContext.getSupportedServices();
-
-    for (String serviceName : services) {
-      Service service = cluster.getService(serviceName);
-      RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
-      StackId targetStack = targetRepositoryVersion.getStackId();
-
-      Collection<ServiceComponent> components = service.getServiceComponents().values();
-      for (ServiceComponent serviceComponent : components) {
-        boolean versionAdvertised = false;
-        try {
-          ComponentInfo ci = m_ambariMetaInfoProvider.get().getComponent(targetStack.getStackName(),
-              targetStack.getStackVersion(), serviceComponent.getServiceType(),
-              serviceComponent.getName());
-
-          versionAdvertised = ci.isVersionAdvertised();
-        } catch (AmbariException e) {
-          LOG.warn("Component {}/{} doesn't exist for stack {}.  Setting version to {}",
-              serviceComponent.getServiceName(), serviceComponent.getName(), targetStack,
-              "UNKNOWN");
-        }
-
-        UpgradeState upgradeStateToSet = UpgradeState.IN_PROGRESS;
-        if (!versionAdvertised) {
-          upgradeStateToSet = UpgradeState.NONE;
-        }
+  private void setDesiredMpacks(UpgradeContext upgradeContext) throws AmbariException {
+    for( ServiceGroup serviceGroup : upgradeContext.getServiceGroups().keySet() ) {
+      StackId targetStack = upgradeContext.getTargetMpack(serviceGroup).getStackId();
+
+      for( Service service : serviceGroup.getServices() ) {
+        Collection<ServiceComponent> components = service.getServiceComponents().values();
+        for (ServiceComponent serviceComponent : components) {
+          boolean versionAdvertised = false;
+          try {
+            ComponentInfo ci = m_ambariMetaInfoProvider.get().getComponent(targetStack.getStackName(),
+                targetStack.getStackVersion(), serviceComponent.getServiceType(),
+                serviceComponent.getName());
+
+            versionAdvertised = ci.isVersionAdvertised();
+          } catch (AmbariException e) {
+            LOG.warn("Component {}/{} doesn't exist for stack {}.  Setting version to {}",
+                serviceComponent.getServiceName(), serviceComponent.getName(), targetStack,
+                "UNKNOWN");
+          }
 
-        for (ServiceComponentHost serviceComponentHost : serviceComponent.getServiceComponentHosts().values()) {
-          if (serviceComponentHost.getUpgradeState() != upgradeStateToSet) {
-            serviceComponentHost.setUpgradeState(upgradeStateToSet);
+          UpgradeState upgradeStateToSet = UpgradeState.IN_PROGRESS;
+          if (!versionAdvertised) {
+            upgradeStateToSet = UpgradeState.NONE;
           }
 
-          // !!! if we aren't version advertised, but there IS a version, set
-          // it.
-          if (!versionAdvertised && !StringUtils.equals("UNKNOWN",
-              serviceComponentHost.getVersion())) {
-            serviceComponentHost.setVersion("UNKNOWN");
+          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 to UNKNOWN
+            if (!versionAdvertised && !StringUtils.equals("UNKNOWN", serviceComponentHost.getVersion())) {
+              serviceComponentHost.setVersion("UNKNOWN");
+            }
           }
         }
-
-        // set component desired repo
-        serviceComponent.setDesiredRepositoryVersion();
       }
+
+      // set the desired mpack
+      StackEntity stackEntity = m_stackDAO.find(targetStack);
+      serviceGroup.setStack(stackEntity);
     }
   }
 
@@ -958,221 +936,223 @@ public class UpgradeHelper {
     Cluster cluster = upgradeContext.getCluster();
     Direction direction = upgradeContext.getDirection();
     String userName = controller.getAuthName();
-    Set<String> servicesInUpgrade = upgradeContext.getSupportedServices();
+    Set<ServiceGroup> serviceGroupsInUpgrade = upgradeContext.getServiceGroups().keySet();
 
     Set<String> clusterConfigTypes = new HashSet<>();
     Set<String> processedClusterConfigTypes = new HashSet<>();
     boolean configsChanged = false;
 
     // merge or revert configurations for any service that needs it
-    for (String serviceName : servicesInUpgrade) {
-      RepositoryVersionEntity sourceRepositoryVersion = upgradeContext.getSourceRepositoryVersion(serviceName);
-      RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
-      StackId sourceStackId = sourceRepositoryVersion.getStackId();
-      StackId targetStackId = targetRepositoryVersion.getStackId();
+    for (ServiceGroup serviceGroup : serviceGroupsInUpgrade) {
+      Mpack sourceMpack = upgradeContext.getSourceMpack(serviceGroup);
+      Mpack targetMpack = upgradeContext.getTargetMpack(serviceGroup);
+
+      StackId sourceStackId = sourceMpack.getStackId();
+      StackId targetStackId = targetMpack.getStackId();
 
       // only work with configurations when crossing stacks
       if (sourceStackId.equals(targetStackId)) {
-        RepositoryVersionEntity associatedRepositoryVersion = upgradeContext.getRepositoryVersion();
         LOG.info(
             "The {} {} {} will not change stack configurations for {} since the source and target are both {}",
             direction.getText(false), direction.getPreposition(),
-            associatedRepositoryVersion.getVersion(), serviceName, targetStackId);
+            targetMpack.getStackId(), serviceGroup.getServiceGroupName(), targetStackId);
 
         continue;
       }
 
-      ConfigHelper configHelper = m_configHelperProvider.get();
+      for( Service service : serviceGroup.getServices() ) {
+        ConfigHelper configHelper = m_configHelperProvider.get();
 
-      // downgrade is easy - just remove the new and make the old current
-      Service service = cluster.getService(serviceName);
-      if (direction == Direction.DOWNGRADE) {
-        cluster.applyLatestConfigurations(targetStackId, service.getServiceId());
-        configsChanged = true;
-       continue;
-      }
+        // downgrade is easy - just remove the new and make the old current
+        if (direction == Direction.DOWNGRADE) {
+          cluster.applyLatestConfigurations(targetStackId, service.getServiceId());
+          configsChanged = true;
+         continue;
+        }
 
-      // the auto-merge must take read-only properties even if they have changed
-      // - if the properties was read-only in the source stack, then we must
-      // take the new stack's value
-      Map<String, Set<String>> readOnlyProperties = getReadOnlyProperties(sourceStackId, service.getServiceType());
+        // the auto-merge must take read-only properties even if they have changed
+        // - if the properties was read-only in the source stack, then we must
+        // take the new stack's value
+        Map<String, Set<String>> readOnlyProperties = getReadOnlyProperties(sourceStackId, service.getServiceType());
 
-      // upgrade is a bit harder - we have to merge new stack configurations in
+        // upgrade is a bit harder - we have to merge new stack configurations in
 
-      // populate a map of default configurations for the service on the old
-      // stack (this is used when determining if a property has been
-      // customized and should be overridden with the new stack value)
-      Map<String, Map<String, String>> oldServiceDefaultConfigsByType = configHelper.getDefaultProperties(
-          sourceStackId, service.getServiceType());
+        // populate a map of default configurations for the service on the old
+        // stack (this is used when determining if a property has been
+        // customized and should be overridden with the new stack value)
+        Map<String, Map<String, String>> oldServiceDefaultConfigsByType = configHelper.getDefaultProperties(
+            sourceStackId, service.getServiceType());
 
-      // populate a map with default configurations from the new stack
-      Map<String, Map<String, String>> newServiceDefaultConfigsByType = configHelper.getDefaultProperties(
-          targetStackId, service.getServiceType());
+        // populate a map with default configurations from the new stack
+        Map<String, Map<String, String>> newServiceDefaultConfigsByType = configHelper.getDefaultProperties(
+            targetStackId, service.getServiceType());
 
-      if (null == oldServiceDefaultConfigsByType || null == newServiceDefaultConfigsByType) {
-        continue;
-      }
+        if (null == oldServiceDefaultConfigsByType || null == newServiceDefaultConfigsByType) {
+          continue;
+        }
 
-      Set<String> foundConfigTypes = new HashSet<>();
+        Set<String> foundConfigTypes = new HashSet<>();
 
-      // find the current, existing configurations for the service
-      List<Config> existingServiceConfigs = new ArrayList<>();
+        // find the current, existing configurations for the service
+        List<Config> existingServiceConfigs = new ArrayList<>();
 
-      List<ServiceConfigEntity> latestServiceConfigs = m_serviceConfigDAO.getLastServiceConfigsForService(
-          //TODO pass serviceGroupName
-          cluster.getClusterId(), service.getServiceId());
+        List<ServiceConfigEntity> latestServiceConfigs = m_serviceConfigDAO.getLastServiceConfigsForService(
+            //TODO pass serviceGroupName
+            cluster.getClusterId(), service.getServiceId());
 
-      for (ServiceConfigEntity serviceConfig : latestServiceConfigs) {
-        List<ClusterConfigEntity> existingConfigurations = serviceConfig.getClusterConfigEntities();
-        for (ClusterConfigEntity currentServiceConfig : existingConfigurations) {
-          String configurationType = currentServiceConfig.getType();
+        for (ServiceConfigEntity serviceConfig : latestServiceConfigs) {
+          List<ClusterConfigEntity> existingConfigurations = serviceConfig.getClusterConfigEntities();
+          for (ClusterConfigEntity currentServiceConfig : existingConfigurations) {
+            String configurationType = currentServiceConfig.getType();
 
-          Config currentClusterConfigForService = cluster.getDesiredConfigByType(configurationType);
-          existingServiceConfigs.add(currentClusterConfigForService);
-          foundConfigTypes.add(configurationType);
+            Config currentClusterConfigForService = cluster.getDesiredConfigByType(configurationType);
+            existingServiceConfigs.add(currentClusterConfigForService);
+            foundConfigTypes.add(configurationType);
+          }
         }
-      }
 
-      // !!! these are the types that come back from the config helper, but are not part of the service.
-      @SuppressWarnings("unchecked")
-      Set<String> missingConfigTypes = new HashSet<>(CollectionUtils.subtract(oldServiceDefaultConfigsByType.keySet(),
-          foundConfigTypes));
+        // !!! these are the types that come back from the config helper, but are not part of the service.
+        @SuppressWarnings("unchecked")
+        Set<String> missingConfigTypes = new HashSet<>(CollectionUtils.subtract(oldServiceDefaultConfigsByType.keySet(),
+            foundConfigTypes));
 
-      for (String missingConfigType : missingConfigTypes) {
-        Config config = cluster.getDesiredConfigByType(missingConfigType);
-        if (null != config) {
-          existingServiceConfigs.add(config);
-          clusterConfigTypes.add(missingConfigType);
+        for (String missingConfigType : missingConfigTypes) {
+          Config config = cluster.getDesiredConfigByType(missingConfigType);
+          if (null != config) {
+            existingServiceConfigs.add(config);
+            clusterConfigTypes.add(missingConfigType);
+          }
         }
-      }
 
-      // now that we have found, old, new, and existing confgs, overlay the
-      // existing on top of the new
-      for (Config existingServiceConfig : existingServiceConfigs) {
-        String configurationType = existingServiceConfig.getType();
+        // now that we have found, old, new, and existing confgs, overlay the
+        // existing on top of the new
+        for (Config existingServiceConfig : existingServiceConfigs) {
+          String configurationType = existingServiceConfig.getType();
 
-        // get current stack default configurations on install
-        Map<String, String> oldServiceDefaultConfigs = oldServiceDefaultConfigsByType.get(
-            configurationType);
+          // get current stack default configurations on install
+          Map<String, String> oldServiceDefaultConfigs = oldServiceDefaultConfigsByType.get(
+              configurationType);
 
-        // NPE sanity for current stack defaults
-        if (null == oldServiceDefaultConfigs) {
-          oldServiceDefaultConfigs = Collections.emptyMap();
-        }
+          // NPE sanity for current stack defaults
+          if (null == oldServiceDefaultConfigs) {
+            oldServiceDefaultConfigs = Collections.emptyMap();
+          }
 
-        // get the existing configurations
-        Map<String, String> existingConfigurations = existingServiceConfig.getProperties();
+          // get the existing configurations
+          Map<String, String> existingConfigurations = existingServiceConfig.getProperties();
 
-        // get the new configurations
-        Map<String, String> newDefaultConfigurations = newServiceDefaultConfigsByType.get(configurationType);
+          // get the new configurations
+          Map<String, String> newDefaultConfigurations = newServiceDefaultConfigsByType.get(configurationType);
 
-        // if the new stack configurations don't have the type, then simply add
-        // all of the existing in
-        if (null == newDefaultConfigurations) {
-          newServiceDefaultConfigsByType.put(configurationType, existingConfigurations);
-          continue;
-        } else {
-          // Remove any configs in the new stack whose value is NULL, unless
-          // they currently exist and the value is not NULL.
-          Iterator<Map.Entry<String, String>> iter = newDefaultConfigurations.entrySet().iterator();
-          while (iter.hasNext()) {
-            Map.Entry<String, String> entry = iter.next();
-            if (entry.getValue() == null) {
-              iter.remove();
+          // if the new stack configurations don't have the type, then simply add
+          // all of the existing in
+          if (null == newDefaultConfigurations) {
+            newServiceDefaultConfigsByType.put(configurationType, existingConfigurations);
+            continue;
+          } else {
+            // Remove any configs in the new stack whose value is NULL, unless
+            // they currently exist and the value is not NULL.
+            Iterator<Map.Entry<String, String>> iter = newDefaultConfigurations.entrySet().iterator();
+            while (iter.hasNext()) {
+              Map.Entry<String, String> entry = iter.next();
+              if (entry.getValue() == null) {
+                iter.remove();
+              }
             }
           }
-        }
 
-        // process every existing configuration property for this configuration type
-        for (Map.Entry<String, String> existingConfigurationEntry : existingConfigurations.entrySet()) {
-          String existingConfigurationKey = existingConfigurationEntry.getKey();
-          String existingConfigurationValue = existingConfigurationEntry.getValue();
-
-          // if there is already an entry, we now have to try to determine if
-          // the value was customized after stack installation
-          if (newDefaultConfigurations.containsKey(existingConfigurationKey)) {
-            String newDefaultConfigurationValue = newDefaultConfigurations.get(
-                existingConfigurationKey);
-
-            if (!StringUtils.equals(existingConfigurationValue, newDefaultConfigurationValue)) {
-              // the new default is different from the existing cluster value;
-              // only override the default value if the existing value differs
-              // from the original stack
-              String oldDefaultValue = oldServiceDefaultConfigs.get(existingConfigurationKey);
-
-              // see if this property is a read-only property which means that
-              // we shouldn't care if it was changed - we should take the new
-              // stack's value
-              Set<String> readOnlyPropertiesForType = readOnlyProperties.get(configurationType);
-              boolean readOnly = (null != readOnlyPropertiesForType
-                  && readOnlyPropertiesForType.contains(existingConfigurationKey));
-
-              if (!readOnly && !StringUtils.equals(existingConfigurationValue, oldDefaultValue)) {
-                // at this point, we've determined that there is a difference
-                // between default values between stacks, but the value was also
-                // customized, so keep the customized value
-                newDefaultConfigurations.put(existingConfigurationKey, existingConfigurationValue);
+          // process every existing configuration property for this configuration type
+          for (Map.Entry<String, String> existingConfigurationEntry : existingConfigurations.entrySet()) {
+            String existingConfigurationKey = existingConfigurationEntry.getKey();
+            String existingConfigurationValue = existingConfigurationEntry.getValue();
+
+            // if there is already an entry, we now have to try to determine if
+            // the value was customized after stack installation
+            if (newDefaultConfigurations.containsKey(existingConfigurationKey)) {
+              String newDefaultConfigurationValue = newDefaultConfigurations.get(
+                  existingConfigurationKey);
+
+              if (!StringUtils.equals(existingConfigurationValue, newDefaultConfigurationValue)) {
+                // the new default is different from the existing cluster value;
+                // only override the default value if the existing value differs
+                // from the original stack
+                String oldDefaultValue = oldServiceDefaultConfigs.get(existingConfigurationKey);
+
+                // see if this property is a read-only property which means that
+                // we shouldn't care if it was changed - we should take the new
+                // stack's value
+                Set<String> readOnlyPropertiesForType = readOnlyProperties.get(configurationType);
+                boolean readOnly = (null != readOnlyPropertiesForType
+                    && readOnlyPropertiesForType.contains(existingConfigurationKey));
+
+                if (!readOnly && !StringUtils.equals(existingConfigurationValue, oldDefaultValue)) {
+                  // at this point, we've determined that there is a difference
+                  // between default values between stacks, but the value was also
+                  // customized, so keep the customized value
+                  newDefaultConfigurations.put(existingConfigurationKey, existingConfigurationValue);
+                }
               }
+            } else {
+              // there is no entry in the map, so add the existing key/value pair
+              newDefaultConfigurations.put(existingConfigurationKey, existingConfigurationValue);
             }
-          } else {
-            // there is no entry in the map, so add the existing key/value pair
-            newDefaultConfigurations.put(existingConfigurationKey, existingConfigurationValue);
           }
-        }
 
-        /*
-        for every new configuration which does not exist in the existing
-        configurations, see if it was present in the current stack
-
-        stack 2.x has foo-site/property (on-ambari-upgrade is false)
-        stack 2.y has foo-site/property
-        the current cluster (on 2.x) does not have it
-
-        In this case, we should NOT add it back as clearly stack advisor has removed it
-        */
-        Iterator<Map.Entry<String, String>> newDefaultConfigurationsIterator = newDefaultConfigurations.entrySet().iterator();
-        while (newDefaultConfigurationsIterator.hasNext()) {
-          Map.Entry<String, String> newConfigurationEntry = newDefaultConfigurationsIterator.next();
-          String newConfigurationPropertyName = newConfigurationEntry.getKey();
-          if (oldServiceDefaultConfigs.containsKey(newConfigurationPropertyName)
-              && !existingConfigurations.containsKey(newConfigurationPropertyName)) {
-            LOG.info(
-                "The property {}/{} exists in both {} and {} but is not part of the current set of configurations and will therefore not be included in the configuration merge",
-                configurationType, newConfigurationPropertyName, sourceStackId, targetStackId);
-
-            // remove the property so it doesn't get merged in
-            newDefaultConfigurationsIterator.remove();
+          /*
+          for every new configuration which does not exist in the existing
+          configurations, see if it was present in the current stack
+
+          stack 2.x has foo-site/property (on-ambari-upgrade is false)
+          stack 2.y has foo-site/property
+          the current cluster (on 2.x) does not have it
+
+          In this case, we should NOT add it back as clearly stack advisor has removed it
+          */
+          Iterator<Map.Entry<String, String>> newDefaultConfigurationsIterator = newDefaultConfigurations.entrySet().iterator();
+          while (newDefaultConfigurationsIterator.hasNext()) {
+            Map.Entry<String, String> newConfigurationEntry = newDefaultConfigurationsIterator.next();
+            String newConfigurationPropertyName = newConfigurationEntry.getKey();
+            if (oldServiceDefaultConfigs.containsKey(newConfigurationPropertyName)
+                && !existingConfigurations.containsKey(newConfigurationPropertyName)) {
+              LOG.info(
+                  "The property {}/{} exists in both {} and {} but is not part of the current set of configurations and will therefore not be included in the configuration merge",
+                  configurationType, newConfigurationPropertyName, sourceStackId, targetStackId);
+
+              // remove the property so it doesn't get merged in
+              newDefaultConfigurationsIterator.remove();
+            }
           }
         }
-      }
 
-      if (null != newServiceDefaultConfigsByType) {
+        if (null != newServiceDefaultConfigsByType) {
+
+          for (String clusterConfigType : clusterConfigTypes) {
+            if (processedClusterConfigTypes.contains(clusterConfigType)) {
+              newServiceDefaultConfigsByType.remove(clusterConfigType);
+            } else {
+              processedClusterConfigTypes.add(clusterConfigType);
+            }
 
-        for (String clusterConfigType : clusterConfigTypes) {
-          if (processedClusterConfigTypes.contains(clusterConfigType)) {
-            newServiceDefaultConfigsByType.remove(clusterConfigType);
-          } else {
-            processedClusterConfigTypes.add(clusterConfigType);
           }
 
-        }
+          Set<String> configTypes = newServiceDefaultConfigsByType.keySet();
+          LOG.warn("The upgrade will create the following configurations for stack {}: {}",
+              targetStackId, StringUtils.join(configTypes, ','));
 
-        Set<String> configTypes = newServiceDefaultConfigsByType.keySet();
-        LOG.warn("The upgrade will create the following configurations for stack {}: {}",
-            targetStackId, StringUtils.join(configTypes, ','));
+          String serviceVersionNote = String.format("%s %s %s", direction.getText(true),
+              direction.getPreposition(), targetMpack.getVersion());
 
-        String serviceVersionNote = String.format("%s %s %s", direction.getText(true),
-            direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion());
+          configHelper.createConfigTypes(cluster, targetStackId, controller,
+              newServiceDefaultConfigsByType, userName, serviceVersionNote);
+          configsChanged = true;
+        }
+      }
 
-        configHelper.createConfigTypes(cluster, targetStackId, controller,
-            newServiceDefaultConfigsByType, userName, serviceVersionNote);
-        configsChanged = true;
+      if (configsChanged) {
+        m_metadataHolder.get().updateData(metadataGenerator.get().getClusterMetadataOnConfigsUpdate(cluster));
+        m_agentConfigsHolder.get().updateData(cluster.getClusterId(), null);
       }
     }
-    if (configsChanged) {
-      m_metadataHolder.get().updateData(metadataGenerator.get().getClusterMetadataOnConfigsUpdate(cluster));
-      m_agentConfigsHolder.get().updateData(cluster.getClusterId(), null);
-    }
   }
 
   /**
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java
index 922b9ee..fff4841 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java
@@ -21,7 +21,6 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.commons.lang.StringUtils;
 
 /**
@@ -31,12 +30,6 @@ import org.apache.commons.lang.StringUtils;
 public class Release {
 
   /**
-   * The type of repository dictates how the repo should be installed and its upgradability.
-   */
-  @XmlElement(name="type")
-  public RepositoryType repositoryType;
-
-  /**
    * The stack id for the repository.
    */
   @XmlElement(name="stack-id")
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 bceffd8..67ce875 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,11 +31,9 @@ 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;
 
@@ -170,13 +168,9 @@ public class RetryUpgradeActionService extends AbstractScheduledService {
       return null;
     }
 
-    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());
+        "Found an active {} with id {}", currentUpgrade.getDirection().getText(false),
+        currentUpgrade.getId());
 
     return currentUpgrade.getRequestId();
   }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
index 76550ba..1399542 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
@@ -46,7 +46,7 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 
 /**
  * Used to represent cluster-based operations.
@@ -109,9 +109,6 @@ public class ClusterGrouping extends Grouping {
     @XmlElement(name="task")
     public Task task;
 
-    @XmlElement(name="scope")
-    public UpgradeScope scope = UpgradeScope.ANY;
-
     /**
      * A condition element with can prevent this stage from being scheduled in
      * the upgrade.
@@ -124,7 +121,7 @@ public class ClusterGrouping extends Grouping {
      */
     @Override
     public String toString() {
-      return Objects.toStringHelper(this).add("id", id).add("title",
+      return MoreObjects.toStringHelper(this).add("id", id).add("title",
           title).omitNullValues().toString();
     }
 
@@ -192,7 +189,7 @@ public class ClusterGrouping extends Grouping {
 
           // only schedule this stage if its service is part of the upgrade
           if (StringUtils.isNotBlank(execution.service)) {
-            if (!upgradeContext.isServiceSupported(execution.service)) {
+            if (!upgradeContext.isSupportedInUpgrade(execution.service)) {
               continue;
             }
           }
@@ -285,13 +282,8 @@ public class ClusterGrouping extends Grouping {
 
     if (StringUtils.isNotBlank(service) && StringUtils.isNotBlank(component)) {
 
-      // !!! if the context is not scoped for the execute-stage, bail
-      if (!ctx.isScoped(execution.scope)) {
-        return null;
-      }
-
       // !!! if the context is targeted and does not include the service, bail
-      if (!ctx.isServiceSupported(service)) {
+      if (!ctx.isSupportedInUpgrade(service)) {
         return null;
       }
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
index 589e766..0bb6029 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
@@ -117,7 +117,7 @@ public class ColocatedGrouping extends Grouping {
           proxy = new TaskProxy();
           proxy.clientOnly = clientOnly;
           proxy.message = getStageText("Preparing",
-              context.getComponentDisplay(service, pc.name), Collections.singleton(host));
+              context.getDisplayName(null, service, pc.name), Collections.singleton(host));
           proxy.tasks.addAll(TaskWrapperBuilder.getTaskList(service, pc.name, singleHostsType, tasks, params));
           proxy.service = service;
           proxy.component = pc.name;
@@ -136,7 +136,7 @@ public class ColocatedGrouping extends Grouping {
           proxy.component = pc.name;
           proxy.type = Type.RESTART;
           proxy.message = getStageText("Restarting",
-              context.getComponentDisplay(service, pc.name), Collections.singleton(host));
+              context.getDisplayName(null, service, pc.name), Collections.singleton(host));
           targetList.add(proxy);
         }
 
@@ -154,7 +154,7 @@ public class ColocatedGrouping extends Grouping {
           proxy.type = type;
           proxy.tasks.addAll(TaskWrapperBuilder.getTaskList(service, pc.name, singleHostsType, tasks, params));
           proxy.message = getStageText("Completing",
-              context.getComponentDisplay(service, pc.name), Collections.singleton(host));
+              context.getDisplayName(null, service, pc.name), Collections.singleton(host));
           targetList.add(proxy);
         }
       }
@@ -313,7 +313,7 @@ public class ColocatedGrouping extends Grouping {
               compLocations.get(host).add(tw.getComponent());
             }
 
-            names.add(ctx.getComponentDisplay(
+            names.add(ctx.getDisplayName(null,
                 tw.getService(), tw.getComponent()));
           }
         }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
index ddd420b..29d6e77 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
@@ -83,9 +83,6 @@ public class Grouping {
   @XmlElement(name="parallel-scheduler")
   public ParallelScheduler parallelScheduler;
 
-  @XmlElement(name="scope")
-  public UpgradeScope scope = UpgradeScope.ANY;
-
   @XmlTransient
   public LifecycleType lifecycle;
 
@@ -245,7 +242,8 @@ public class Grouping {
         for (Set<String> hostSubset : hostSets) {
           batchNum++;
 
-          String stageText = getStageText(verb, ctx.getComponentDisplay(service, pc.name), hostSubset, batchNum, numBatchesNeeded);
+          String stageText = getStageText(verb, ctx.getDisplayName(null, service, pc.name),
+              hostSubset, batchNum, numBatchesNeeded);
 
           StageWrapper stage = new StageWrapper(
               type,
@@ -277,7 +275,7 @@ public class Grouping {
         tasks.add(new TaskWrapper(
             service, "", Collections.emptySet(), new ServiceCheckTask()));
 
-        displays.add(upgradeContext.getServiceDisplay(service));
+        displays.add(upgradeContext.getDisplayName(null, service));
       }
 
       if (upgradeContext.getDirection().isUpgrade() && m_serviceCheck
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 e27fa8c..ddb38f4 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
@@ -23,23 +23,26 @@ import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.Role;
 import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
 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;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.Mpack;
 import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
@@ -106,7 +109,7 @@ public class HostOrderGrouping extends Grouping {
 
     @Override
     public List<StageWrapper> build(UpgradeContext upgradeContext,
-        List<StageWrapper> stageWrappers) {
+        List<StageWrapper> stageWrappers) throws AmbariException {
 
       List<StageWrapper> wrappers = new ArrayList<>(stageWrappers);
 
@@ -136,7 +139,7 @@ public class HostOrderGrouping extends Grouping {
      *          the list of hostnames
      * @return the wrappers for a host
      */
-    private List<StageWrapper> buildHosts(UpgradeContext upgradeContext, List<String> hosts) {
+    private List<StageWrapper> buildHosts(UpgradeContext upgradeContext, List<String> hosts) throws AmbariException {
       if (CollectionUtils.isEmpty(hosts)) {
         return Collections.emptyList();
       }
@@ -174,13 +177,12 @@ 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.getHosts().contains(hostName)) {
-            RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
-                sch.getServiceName());
+            Set<Mpack> targetMpacks = upgradeContext.getTargetMpacks();
 
-            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(),
-                targetRepositoryVersion.getVersion());
+            LOG.warn(
+                "Host {} could not be orchestrated. Either there are no components for {}/{} "
+                    + "or the target mpacks {} are already current.",
+                hostName, sch.getServiceName(), sch.getServiceComponentName(), targetMpacks);
 
             continue;
           }
@@ -231,7 +233,12 @@ public class HostOrderGrouping extends Grouping {
           // create task wrappers
           List<TaskWrapper> taskWrappers = new ArrayList<>();
           for (HostRoleCommand command : stageCommandsForHost) {
-            StackId stackId = upgradeContext.getRepositoryVersion().getStackId();
+            ExecutionCommandWrapper wrapper = command.getExecutionCommandWrapper();
+            String serviceGroupName = wrapper.getExecutionCommand().getServiceGroupName();
+            ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupName);
+            Mpack targetMpack = upgradeContext.getTargetMpack(serviceGroup);
+            StackId stackId = targetMpack.getStackId();
+
             String componentName = command.getRole().name();
 
             String serviceName = null;
@@ -318,7 +325,7 @@ public class HostOrderGrouping extends Grouping {
         }
 
         StageWrapper wrapper = new StageWrapper(StageWrapper.Type.SERVICE_CHECK,
-            String.format("Service Check %s", upgradeContext.getServiceDisplay(serviceName)),
+            String.format("Service Check %s", upgradeContext.getDisplayName(null, serviceName)),
             new TaskWrapper(serviceName, "", Collections.emptySet(), new ServiceCheckTask()));
 
         wrappers.add(wrapper);
@@ -333,11 +340,13 @@ public class HostOrderGrouping extends Grouping {
      * @param sch             the host component
      * @return                {@code true} if the host component advertises its version
      */
-    private boolean isVersionAdvertised(UpgradeContext upgradeContext, ServiceComponentHost sch) {
-      RepositoryVersionEntity targetRepositoryVersion = upgradeContext.getTargetRepositoryVersion(
-          sch.getServiceName());
-
-      StackId targetStack = targetRepositoryVersion.getStackId();
+    private boolean isVersionAdvertised(UpgradeContext upgradeContext, ServiceComponentHost sch)
+        throws AmbariException {
+      long serviceGroupId = sch.getServiceGroupId();
+      Cluster cluster = upgradeContext.getCluster();
+      ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupId);
+      Mpack targetMpack = upgradeContext.getTargetMpack(serviceGroup);
+      StackId targetStack = targetMpack.getStackId();
 
       try {
         ComponentInfo component = upgradeContext.getAmbariMetaInfo().getComponent(
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
index 3fc8e2c..cee28e8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
@@ -143,7 +143,7 @@ public class ServiceCheckGrouping extends Grouping {
       for (String service : priorityServices) {
         if (checkServiceValidity(upgradeContext, service, serviceMap)) {
           StageWrapper wrapper = new ServiceCheckStageWrapper(service,
-              upgradeContext.getServiceDisplay(service), true);
+              upgradeContext.getDisplayName(null, service), true);
 
           result.add(wrapper);
           clusterServices.remove(service);
@@ -159,7 +159,7 @@ public class ServiceCheckGrouping extends Grouping {
 
           if (checkServiceValidity(upgradeContext, service, serviceMap)) {
             StageWrapper wrapper = new ServiceCheckStageWrapper(service,
-                upgradeContext.getServiceDisplay(service), false);
+                upgradeContext.getDisplayName(null, service), false);
 
             result.add(wrapper);
           }
@@ -185,7 +185,6 @@ public class ServiceCheckGrouping extends Grouping {
             ServiceInfo si = m_metaInfo.getService(stackId.getStackName(), stackId.getStackVersion(), svc.getServiceType());
             CommandScriptDefinition script = si.getCommandScript();
             if (null != script && null != script.getScript() && !script.getScript().isEmpty()) {
-              ctx.setServiceDisplay(service, si.getDisplayName());
               return true;
             }
           } catch (AmbariException e) {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
index c26aadf..d3b42ac 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.serveraction.upgrades.AutoSkipFailedSummaryAction;
 import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.state.UpgradeContext;
@@ -86,7 +87,7 @@ public abstract class StageWrapperBuilder {
    *          the upgrade context (not {@code null}).
    * @return a list of stages, never {@code null}
    */
-  public final List<StageWrapper> build(UpgradeContext upgradeContext) {
+  public final List<StageWrapper> build(UpgradeContext upgradeContext) throws AmbariException {
     List<StageWrapper> stageWrappers = beforeBuild(upgradeContext);
     stageWrappers = build(upgradeContext, stageWrappers);
     stageWrappers = afterBuild(upgradeContext, stageWrappers);
@@ -118,7 +119,7 @@ public abstract class StageWrapperBuilder {
    * @return the stage wrapper list, (never {@code null})
    */
   public abstract List<StageWrapper> build(UpgradeContext upgradeContext,
-      List<StageWrapper> stageWrappers);
+      List<StageWrapper> stageWrappers) throws AmbariException;
 
   /**
    * Performs any post-processing that needs to be performed on the list of
@@ -229,7 +230,6 @@ public abstract class StageWrapperBuilder {
 
     List<Task> tasks = new ArrayList<>();
     for (Task t : interim) {
-      boolean taskPassesScoping = context.isScoped(t.scope);
       boolean taskPassesCondition = true;
 
       // tasks can have conditions on them, so check to make sure the condition is satisfied
@@ -237,7 +237,7 @@ public abstract class StageWrapperBuilder {
         taskPassesCondition = false;
       }
 
-      if (taskPassesScoping && taskPassesCondition) {
+      if (taskPassesCondition) {
         tasks.add(t);
       }
     }
@@ -253,9 +253,7 @@ public abstract class StageWrapperBuilder {
    */
   protected Task resolveTask(UpgradeContext context, ProcessingComponent pc) {
     if (null != pc.tasks && 1 == pc.tasks.size()) {
-      if (context.isScoped(pc.tasks.get(0).scope)) {
-        return pc.tasks.get(0);
-      }
+      return pc.tasks.get(0);
     }
 
     return null;
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
index 3426a3a..2751d1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
@@ -69,13 +69,6 @@ public abstract class Task {
    */
   public abstract String getActionVerb();
 
-  /**
-   * The scope for the task
-   */
-  @XmlElement(name = "scope")
-  public UpgradeScope scope = UpgradeScope.ANY;
-
-
   @Override
   public String toString() {
     return getType().toString();
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeScope.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeScope.java
deleted file mode 100644
index 0afe353..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeScope.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.state.stack.upgrade;
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlEnumValue;
-
-import com.google.gson.annotations.SerializedName;
-
-/**
- * Indicates the scope of a group or task
- */
-@XmlEnum
-public enum UpgradeScope {
-
-  /**
-   * Used only when completely upgrading the cluster.
-   */
-  @XmlEnumValue("COMPLETE")
-  @SerializedName("rolling_upgrade")
-  COMPLETE,
-
-  /**
-   * Used only when partially upgrading the cluster.
-   */
-  @XmlEnumValue("PARTIAL")
-  @SerializedName("partial")
-  PARTIAL,
-
-  /**
-   * Used for any scoped upgrade.
-   */
-  @XmlEnumValue("ANY")
-  @SerializedName("any")
-  ANY;
-}
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 9acb83f..cd851cf 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -966,12 +966,12 @@ CREATE TABLE upgrade (
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
   skip_failures SMALLINT DEFAULT 0 NOT NULL,
   skip_sc_failures SMALLINT DEFAULT 0 NOT NULL,
   downgrade_allowed SMALLINT DEFAULT 1 NOT NULL,
+  is_revert SMALLINT DEFAULT 0 NOT NULL,
   revert_allowed SMALLINT DEFAULT 0 NOT NULL,
   suspended SMALLINT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
@@ -1004,14 +1004,12 @@ CREATE TABLE upgrade_item (
 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,
   service_group_id BIGINT NOT NULL,
   source_mpack_id BIGINT NOT NULL,
   target_mpack_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 UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
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 9ee0646..d89c454 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -983,12 +983,12 @@ CREATE TABLE upgrade (
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
   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,
+  is_revert TINYINT(1) NOT NULL DEFAULT 0,
   revert_allowed TINYINT(1) NOT NULL DEFAULT 0,
   suspended TINYINT(1) DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
@@ -1021,14 +1021,12 @@ CREATE TABLE upgrade_item (
 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,
   service_group_id BIGINT NOT NULL,
   source_mpack_id BIGINT NOT NULL,
   target_mpack_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 UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
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 9614ff9..afed777 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -961,12 +961,12 @@ CREATE TABLE upgrade (
   cluster_id NUMBER(19) NOT NULL,
   request_id NUMBER(19) NOT NULL,
   direction VARCHAR2(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR2(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_package VARCHAR2(255) NOT NULL,
   upgrade_type VARCHAR2(32) NOT NULL,
   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,
+  is_revert NUMBER(1) DEFAULT 0 NOT NULL,
   revert_allowed NUMBER(1) DEFAULT 0 NOT NULL,
   suspended NUMBER(1) DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
@@ -999,14 +999,12 @@ CREATE TABLE upgrade_item (
 CREATE TABLE upgrade_history(
   id NUMBER(19) NOT NULL,
   upgrade_id NUMBER(19) NOT NULL,
-  service_name VARCHAR2(255) NOT NULL,
-  component_name VARCHAR2(255) NOT NULL,
   service_group_id NUMBER(19) NOT NULL,
   source_mpack_id NUMBER(19) NOT NULL,
   target_mpack_id NUMBER(19) NOT NULL,
   CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
   CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
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 cd16fa4..f7b6c0c 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -967,12 +967,12 @@ CREATE TABLE upgrade (
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
   skip_failures SMALLINT DEFAULT 0 NOT NULL,
   skip_sc_failures SMALLINT DEFAULT 0 NOT NULL,
   downgrade_allowed SMALLINT DEFAULT 1 NOT NULL,
+  is_revert SMALLINT DEFAULT 0 NOT NULL,
   revert_allowed SMALLINT DEFAULT 0 NOT NULL,
   suspended SMALLINT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
@@ -1005,14 +1005,12 @@ CREATE TABLE upgrade_item (
 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,
   service_group_id BIGINT NOT NULL,
   source_mpack_id BIGINT NOT NULL,
   target_mpack_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 UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
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 bca753b..77daf73 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -961,12 +961,12 @@ CREATE TABLE upgrade (
   cluster_id NUMERIC(19) NOT NULL,
   request_id NUMERIC(19) NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   skip_failures BIT NOT NULL DEFAULT 0,
   skip_sc_failures BIT NOT NULL DEFAULT 0,
   downgrade_allowed BIT NOT NULL DEFAULT 1,
+  is_revert BIT NOT NULL DEFAULT 0,
   revert_allowed BIT NOT NULL DEFAULT 0,
   suspended BIT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY (upgrade_id),
@@ -999,14 +999,12 @@ CREATE TABLE upgrade_item (
 CREATE TABLE upgrade_history(
   id NUMERIC(19) NOT NULL,
   upgrade_id NUMERIC(19) NOT NULL,
-  service_name VARCHAR(255) NOT NULL,
-  component_name VARCHAR(255) NOT NULL,
   service_group_id NUMERIC(19) NOT NULL,
   source_mpack_id NUMERIC(19) NOT NULL,
   target_mpack_id NUMERIC(19) NOT NULL,
   CONSTRAINT PK_upgrade_hist PRIMARY KEY (id),
   CONSTRAINT FK_upgrade_hist_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id),
-  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
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 66638ea..4bcc399 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -984,12 +984,12 @@ CREATE TABLE upgrade (
   cluster_id BIGINT NOT NULL,
   request_id BIGINT NOT NULL,
   direction VARCHAR(255) DEFAULT 'UPGRADE' NOT NULL,
-  orchestration VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   upgrade_package VARCHAR(255) NOT NULL,
   upgrade_type VARCHAR(32) NOT NULL,
   skip_failures BIT NOT NULL DEFAULT 0,
   skip_sc_failures BIT NOT NULL DEFAULT 0,
   downgrade_allowed BIT NOT NULL DEFAULT 1,
+  is_revert BIT NOT NULL DEFAULT 0,
   revert_allowed BIT NOT NULL DEFAULT 0,
   suspended BIT DEFAULT 0 NOT NULL,
   CONSTRAINT PK_upgrade PRIMARY KEY CLUSTERED (upgrade_id),
@@ -1022,14 +1022,12 @@ CREATE TABLE upgrade_item (
 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,
   service_group_id BIGINT NOT NULL,
   source_mpack_id BIGINT NOT NULL,
   target_mpack_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 UQ_upgrade_hist UNIQUE (upgrade_id, component_name, service_name),
+  CONSTRAINT UQ_upgrade_hist UNIQUE (upgrade_id, service_group_id),
   CONSTRAINT FK_upgrade_hist_svc_grp_id FOREIGN KEY (service_group_id) REFERENCES servicegroups (id),
   CONSTRAINT FK_upgrade_hist_src_mpack_id FOREIGN KEY (source_mpack_id) REFERENCES mpacks (id),
   CONSTRAINT FK_upgrade_hist_tgt_mpack_id FOREIGN KEY (target_mpack_id) REFERENCES mpacks (id),
diff --git a/ambari-server/src/main/resources/upgrade-pack.xsd b/ambari-server/src/main/resources/upgrade-pack.xsd
index b406cfa..9f3005e 100644
--- a/ambari-server/src/main/resources/upgrade-pack.xsd
+++ b/ambari-server/src/main/resources/upgrade-pack.xsd
@@ -61,14 +61,6 @@
     </xs:restriction>
   </xs:simpleType>
   
-  <xs:simpleType name="scope-type">
-    <xs:restriction base="xs:string">
-      <xs:enumeration value="COMPLETE" />
-      <xs:enumeration value="PARTIAL" />
-      <xs:enumeration value="ANY" />
-    </xs:restriction>
-  </xs:simpleType>
-  
   <xs:simpleType name="security-type">
     <xs:restriction base="xs:string">
       <xs:enumeration value="none" />
@@ -133,7 +125,6 @@
   <xs:complexType name="abstract-group-type" abstract="true">
     <xs:sequence>
       <xs:element name="condition" type="abstract-condition-type" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="scope" type="scope-type" minOccurs="0" />
       <xs:element name="direction" type="direction-type" minOccurs="0" />
       <xs:element name="service-check" minOccurs="0" type="xs:boolean" />
       <xs:element name="skippable" minOccurs="0" type="xs:boolean" />
@@ -172,7 +163,6 @@
               <xs:sequence>
                 <xs:element name="condition" type="abstract-condition-type" minOccurs="0" maxOccurs="1"/>
                 <xs:element name="direction" type="direction-type" minOccurs="0" maxOccurs="1"/>
-                <xs:element name="scope" type="scope-type" minOccurs="0" maxOccurs="1"/>
                 <xs:element name="task" type="abstract-task-type" minOccurs="1" maxOccurs="1"/>
               </xs:sequence>              
               <xs:attribute name="title" type="xs:string" />
@@ -269,7 +259,6 @@
   <xs:complexType name="abstract-task-type" abstract="true">
     <xs:sequence>
       <xs:element name="condition" type="abstract-condition-type" minOccurs="0" maxOccurs="1" />
-      <xs:element name="scope" minOccurs="0" type="scope-type" />
       <xs:element name="summary" minOccurs="0" />
     </xs:sequence>
     <xs:attribute name="sequential" use="optional" type="xs:boolean" />
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 a8e21f6..586eccd 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_REPO_VERSION_ID, "1234");
+    properties.put(UpgradeResourceProvider.UPGRADE_PLAN_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 ID(1234), 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), Upgrade Plan ID(1234), Upgrade type(ROLLING), Cluster name(mycluster)";
 
     Assert.assertTrue("Class mismatch", event instanceof AddUpgradeRequestAuditEvent);
     Assert.assertEquals(expected, actual);
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheckTest.java
deleted file mode 100644
index 141a749..0000000
--- a/ambari-server/src/test/java/org/apache/ambari/server/checks/RequiredServicesInRepositoryCheckTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.checks;
-
-import static org.mockito.Mockito.mock;
-
-import java.util.Set;
-
-import org.apache.ambari.annotations.Experimental;
-import org.apache.ambari.annotations.ExperimentalFeature;
-import org.apache.ambari.server.controller.PrereqCheckRequest;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.stack.PrereqCheckStatus;
-import org.apache.ambari.server.state.stack.PrerequisiteCheck;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import com.google.common.collect.Sets;
-import com.google.inject.Provider;
-
-/**
- * Tests {@link RequiredServicesInRepositoryCheck}.
- */
-@Ignore
-@Experimental(feature = ExperimentalFeature.UNIT_TEST_REQUIRED)
-@RunWith(MockitoJUnitRunner.class)
-public class RequiredServicesInRepositoryCheckTest {
-
-  private static final String CLUSTER_NAME = "c1";
-
-  private RequiredServicesInRepositoryCheck m_requiredServicesCheck;
-
-  /**
-   * Used to return the missing dependencies for the test.
-   */
-  private Set<String> m_missingDependencies = Sets.newTreeSet();
-
-  @Before
-  public void setUp() throws Exception {
-    final Clusters clusters = mock(Clusters.class);
-    m_requiredServicesCheck = new RequiredServicesInRepositoryCheck();
-    m_requiredServicesCheck.clustersProvider = new Provider<Clusters>() {
-      @Override
-      public Clusters get() {
-        return clusters;
-      }
-    };
-
-    final Cluster cluster = Mockito.mock(Cluster.class);
-    Mockito.when(cluster.getClusterId()).thenReturn(1L);
-    Mockito.when(clusters.getCluster(CLUSTER_NAME)).thenReturn(cluster);
-  }
-
-  /**
-   * Tests that a no missing services results in a passed test.
-   *
-   * @throws Exception
-   */
-  @Test
-  public void testNoMissingServices() throws Exception {
-    PrereqCheckRequest request = new PrereqCheckRequest(CLUSTER_NAME);
-
-    PrerequisiteCheck check = new PrerequisiteCheck(null, CLUSTER_NAME);
-    m_requiredServicesCheck.perform(check, request);
-    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
-    Assert.assertTrue(check.getFailedDetail().isEmpty());
-  }
-
-  /**
-   * Tests that a missing required service causes the test to fail.
-   *
-   * @throws Exception
-   */
-  @Test
-  public void testMissingRequiredService() throws Exception {
-    PrereqCheckRequest request = new PrereqCheckRequest(CLUSTER_NAME);
-
-    m_missingDependencies.add("BAR");
-
-    PrerequisiteCheck check = new PrerequisiteCheck(null, CLUSTER_NAME);
-    m_requiredServicesCheck.perform(check, request);
-    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
-    Assert.assertFalse(check.getFailedDetail().isEmpty());
-  }
-}
\ No newline at end of file
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProviderTest.java
index a19acb4..6a89cb1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProviderTest.java
@@ -146,7 +146,7 @@ public class PreUpgradeCheckResourceProviderTest {
     Predicate predicate = builder.property(PreUpgradeCheckResourceProvider.UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").and()
         .property(PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID).equals("upgrade_pack11").and()
         .property(PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID).equals(UpgradeType.EXPRESS).and()
-        .property(PreUpgradeCheckResourceProvider.UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID).equals("1").toPredicate();
+        .property(PreUpgradeCheckResourceProvider.UPGRADE_CHECK_UPGRADE_PLAN_ID).equals("1").toPredicate();
 
 
     System.out.println("PreUpgradeCheckResourceProvider - " + provider);
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
index aaee216..30f29a6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
@@ -269,8 +269,6 @@ public class UpgradeSummaryResourceProviderTest {
     upgrade.setUpgradeType(UpgradeType.ROLLING);
     upgrade.setDirection(Direction.UPGRADE);
 
-
-    upgrade.setRepositoryVersion(null);
     upgradeDAO.create(upgrade);
 
     // Resource used to make assertions.
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
index 4c5f38b..358f19d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
@@ -42,12 +42,14 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.RequestDAO;
+import org.apache.ambari.server.orm.dao.ServiceGroupDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.MpackEntity;
 import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
 import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
+import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
@@ -321,23 +323,13 @@ public class ComponentVersionCheckActionTest {
     cluster.setCurrentStackVersion(sourceStack);
     cluster.setDesiredStackVersion(targetStack);
 
+    ServiceGroupDAO serviceGroupDAO = m_injector.getInstance(ServiceGroupDAO.class);
+    ServiceGroupEntity serviceGroupEntity = serviceGroupDAO.findByPK(serviceGroup.getServiceGroupId());
+
     // tell the upgrade that HDFS is upgrading - without this, no services will
     // be participating in the upgrade
     UpgradeEntity upgrade = cluster.getUpgradeInProgress();
-    UpgradeHistoryEntity history = new UpgradeHistoryEntity();
-    history.setUpgrade(upgrade);
-    history.setServiceName("HDFS");
-    history.setComponentName("NAMENODE");
-    history.setFromRepositoryVersion(null);
-    history.setTargetRepositoryVersion(null);
-    upgrade.addHistory(history);
-
-    history = new UpgradeHistoryEntity();
-    history.setUpgrade(upgrade);
-    history.setServiceName("HDFS");
-    history.setComponentName("DATANODE");
-    history.setFromRepositoryVersion(null);
-    history.setTargetRepositoryVersion(null);
+    UpgradeHistoryEntity history = new UpgradeHistoryEntity(upgrade, serviceGroupEntity, sourceMpack, targetMpack);
     upgrade.addHistory(history);
 
     UpgradeDAO upgradeDAO = m_injector.getInstance(UpgradeDAO.class);
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
index 04ec1b8..1601b1e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
@@ -42,9 +42,11 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.RequestDAO;
+import org.apache.ambari.server.orm.dao.ServiceGroupDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.MpackEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
+import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
 import org.apache.ambari.server.serveraction.ServerAction;
@@ -313,15 +315,13 @@ public class CreateAndConfigureActionTest {
     upgradeEntity.setUpgradePackage("");
     upgradeEntity.setUpgradeType(UpgradeType.EXPRESS);
 
-    for (Service service : cluster.getServices()) {
-      Map<String, ServiceComponent> components = service.getServiceComponents();
-      for (String componentName : components.keySet()) {
-        UpgradeHistoryEntity history = new UpgradeHistoryEntity();
-        history.setUpgrade(upgradeEntity);
-        history.setServiceName(service.getName());
-        history.setComponentName(componentName);
-        upgradeEntity.addHistory(history);
-      }
+    ServiceGroupDAO serviceGroupDAO = m_injector.getInstance(ServiceGroupDAO.class);
+    for( ServiceGroup serviceGroup : cluster.getServiceGroups().values() ) {
+      ServiceGroupEntity serviceGroupEntity = serviceGroupDAO.findByPK(serviceGroup.getServiceGroupId());
+      UpgradeHistoryEntity history = new UpgradeHistoryEntity(upgradeEntity, serviceGroupEntity,
+          mpack211, mpackEntity);
+
+      upgradeEntity.addHistory(history);
     }
 
     upgradeDAO.create(upgradeEntity);

-- 
To stop receiving notification emails like this one, please contact
jonathanhurley@apache.org.