You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/09/16 00:12:45 UTC

ambari git commit: AMBARI-13052. Stop-and-Start Upgrade: HDP 2.1->2.3 needs to stop services using 2.1, and start using 2.3 (alejandro)

Repository: ambari
Updated Branches:
  refs/heads/branch-dev-stop-all-upgrade a3fb2d24b -> 247e728c0


AMBARI-13052. Stop-and-Start Upgrade: HDP 2.1->2.3 needs to stop services using 2.1, and start using 2.3 (alejandro)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/247e728c
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/247e728c
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/247e728c

Branch: refs/heads/branch-dev-stop-all-upgrade
Commit: 247e728c09873d2c0209712bc394a95c76d6593d
Parents: a3fb2d2
Author: Alejandro Fernandez <af...@hortonworks.com>
Authored: Fri Sep 11 17:24:58 2015 -0700
Committer: Alejandro Fernandez <af...@hortonworks.com>
Committed: Tue Sep 15 15:10:22 2015 -0700

----------------------------------------------------------------------
 .../AmbariCustomCommandExecutionHelper.java     |  11 +-
 .../AmbariManagementControllerImpl.java         |   6 +-
 .../ClusterStackVersionResourceProvider.java    |   4 +-
 .../internal/UpgradeResourceProvider.java       |  39 ++++--
 .../upgrades/UpdateDesiredStackAction.java      | 139 +++++++++++++++++++
 .../ambari/server/state/UpgradeContext.java     |  36 +++++
 .../ambari/server/state/UpgradeHelper.java      |   4 +
 .../server/state/stack/upgrade/Grouping.java    |   2 +-
 .../state/stack/upgrade/ServerActionTask.java   |   2 -
 .../stack/upgrade/UpdateStackGrouping.java      |  36 +++++
 .../HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml |   8 ++
 .../HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml |   8 ++
 .../internal/UpgradeResourceProviderTest.java   |   2 +-
 .../server/state/stack/UpgradePackTest.java     |  18 ++-
 .../server/upgrade/UpgradeCatalog212Test.java   |   3 +
 .../2.1.1/upgrades/upgrade_test_nonrolling.xml  |   8 ++
 16 files changed, 301 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index 6ac3ed7..2c08396 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -1043,11 +1043,12 @@ public class AmbariCustomCommandExecutionHelper {
    *
    * @param actionExecContext  the context
    * @param cluster            the cluster for the command
+   * @param stackId            the effective stack id to use.
    *
    * @return a wrapper of the imporant JSON structures to add to a stage
    */
   public ExecuteCommandJson getCommandJson(ActionExecutionContext actionExecContext,
-      Cluster cluster) throws AmbariException {
+      Cluster cluster, StackId stackId) throws AmbariException {
 
     Map<String, String> commandParamsStage = StageUtils.getCommandParamsStage(actionExecContext);
     Map<String, String> hostParamsStage = new HashMap<String, String>();
@@ -1057,8 +1058,8 @@ public class AmbariCustomCommandExecutionHelper {
     if (null != cluster) {
       clusterHostInfo = StageUtils.getClusterHostInfo(
           cluster);
-      hostParamsStage = createDefaultHostParams(cluster);
-      StackId stackId = cluster.getDesiredStackVersion();
+      // Important, because this runs during Stack Uprade, it needs to use the effective Stack Id.
+      hostParamsStage = createDefaultHostParams(cluster, stackId);
       String componentName = null;
       String serviceName = null;
       if (actionExecContext.getOperationLevel() != null) {
@@ -1089,6 +1090,10 @@ public class AmbariCustomCommandExecutionHelper {
 
   Map<String, String> createDefaultHostParams(Cluster cluster) {
     StackId stackId = cluster.getDesiredStackVersion();
+    return createDefaultHostParams(cluster, stackId);
+  }
+
+  Map<String, String> createDefaultHostParams(Cluster cluster, StackId stackId) {
     TreeMap<String, String> hostLevelParams = new TreeMap<String, String>();
     hostLevelParams.put(JDK_LOCATION, managementController.getJdkResourceUrl());
     hostLevelParams.put(JAVA_HOME, managementController.getJavaHome());

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index a7f206a..86ab306 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -3297,7 +3297,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         actionManager,
         actionRequest);
 
-    ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(actionExecContext, cluster);
+    StackId stackId = null;
+    if (null != cluster) {
+      stackId = cluster.getDesiredStackVersion();
+    }
+    ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(actionExecContext, cluster, stackId);
     String commandParamsForStage = jsons.getCommandParamsForStage();
 
     // Ensure that the specified requestContext (if any) is set as the request context

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
index 6133885..08e457e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
@@ -654,9 +654,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
         throw new SystemException(detailedOutput);
       }
     } catch (AmbariException e) {
-      throw new SystemException("Can not perform request", e);
+      throw new SystemException("Cannot perform request", e);
     } catch (InterruptedException e) {
-      throw new SystemException("Can not perform request", e);
+      throw new SystemException("Cannot perform request", e);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index c73f9d4..2d41673 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
@@ -95,6 +95,7 @@ import org.apache.ambari.server.state.stack.upgrade.ServerSideActionTask;
 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.UpgradeType;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent;
 import org.apache.commons.lang.StringUtils;
@@ -613,9 +614,21 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     List<UpgradeGroupEntity> groupEntities = new ArrayList<UpgradeGroupEntity>();
     RequestStageContainer req = createRequest(direction, version);
 
-    // desired configs must be set before creating stages because the config tag
-    // names are read and set on the command for filling in later
-    processConfigurations(targetStackId.getStackName(), cluster, version, direction, pack);
+    /**
+    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.UpdateDesiredStackAction}
+    at the appropriate moment during the orchestration.
+    **/
+    if (pack.getType() == UpgradeType.ROLLING) {
+      // Desired configs must be set before creating stages because the config tag
+      // names are read and set on the command for filling in later
+      applyStackAndProcessConfigurations(targetStackId.getStackName(), cluster, version, direction, pack);
+    }
 
     // TODO: for cross-stack upgrade, merge a new config upgrade pack from all
     // target stacks involved into upgrade and pass it into method
@@ -643,6 +656,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
               itemEntity.setTasks(wrapper.getTasksJson());
               itemEntity.setHosts(wrapper.getHostsJson());
               itemEntities.add(itemEntity);
+              
+              // At this point, need to change the effective Stack Id so that subsequent tasks run on the newer value.
+              // TODO AMBARI-12698, check if this works during a Stop-the-World Downgrade.
+              if (UpdateStackGrouping.class.equals(group.groupClass)) {
+                ctx.setEffectiveStackId(ctx.getTargetStackId());
+              }
 
               injectVariables(configHelper, cluster, itemEntity);
 
@@ -722,7 +741,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    *          which services are effected.
    * @throws AmbariException
    */
-  void processConfigurations(String stackName, Cluster cluster, String version, Direction direction, UpgradePack upgradePack)
+  void applyStackAndProcessConfigurations(String stackName, Cluster cluster, String version, Direction direction, UpgradePack upgradePack)
       throws AmbariException {
     RepositoryVersionEntity targetRve = s_repoVersionDAO.findByStackNameAndVersion(stackName, version);
     if (null == targetRve) {
@@ -823,7 +842,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           continue;
         }
 
-        // NPE sanity, althought shouldn't even happen since we are iterating
+        // NPE sanity, although shouldn't even happen since we are iterating
         // over the desired configs to start with
         Config currentClusterConfig = cluster.getDesiredConfigByType(configurationType);
         if (null == currentClusterConfig) {
@@ -953,7 +972,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     // service, it is necessary to set the
     // service_package_folder and hooks_folder params.
     AmbariMetaInfo ambariMetaInfo = s_metaProvider.get();
-    StackId stackId = cluster.getDesiredStackVersion();
+    StackId stackId = context.getEffectiveStackId();
 
     StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(),
         stackId.getStackVersion());
@@ -974,7 +993,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false)));
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster);
+        cluster, context.getEffectiveStackId());
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(),
@@ -1061,7 +1080,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setIgnoreMaintenance(true);
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster);
+        cluster, context.getEffectiveStackId());
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(),
@@ -1113,7 +1132,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     actionContext.setIgnoreMaintenance(true);
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster);
+        cluster, context.getEffectiveStackId());
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), entity.getText(),
@@ -1222,7 +1241,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
 
     ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext,
-        cluster);
+        cluster, context.getEffectiveStackId());
 
     Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
         cluster.getClusterName(), cluster.getClusterId(), stageText, jsons.getClusterHostInfo(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java
new file mode 100644
index 0000000..b676c9b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java
@@ -0,0 +1,139 @@
+/**
+ * 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 com.google.inject.Inject;
+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.api.services.AmbariMetaInfo;
+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.StackId;
+import org.apache.ambari.server.state.StackInfo;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 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#NON_ROLLING}, 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 UpdateDesiredStackAction extends AbstractServerAction {
+
+  /**
+   * The original "current" stack of the cluster before the upgrade started.
+   * This is the same regardless of whether the current direction is
+   * {@link org.apache.ambari.server.state.stack.upgrade.Direction#UPGRADE} or {@link org.apache.ambari.server.state.stack.upgrade.Direction#DOWNGRADE}.
+   */
+  public static final String ORIGINAL_STACK_KEY = "original_stack";
+
+  /**
+   * The target upgrade stack before the upgrade started. This is the same
+   * regardless of whether the current direction is {@link org.apache.ambari.server.state.stack.upgrade.Direction#UPGRADE} or
+   * {@link org.apache.ambari.server.state.stack.upgrade.Direction#DOWNGRADE}.
+   */
+  public static final String TARGET_STACK_KEY = "target_stack";
+
+  /**
+   * The Cluster that this ServerAction implementation is executing on.
+   */
+  @Inject
+  private Clusters clusters;
+
+  @Inject
+  private AmbariMetaInfo ambariMetaInfo;
+
+  @Override
+  public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext)
+      throws AmbariException, InterruptedException {
+    Map<String, String> commandParams = getExecutionCommand().getCommandParams();
+
+    StackId originalStackId = new StackId(commandParams.get(ORIGINAL_STACK_KEY));
+    StackId targetStackId = new StackId(commandParams.get(TARGET_STACK_KEY));
+    String clusterName = getExecutionCommand().getClusterName();
+
+    return updateDesiredStack(clusterName, originalStackId, targetStackId);
+  }
+
+  /**
+   * Set the cluster's Desired Stack Id during an upgrade.
+   *
+   * @param clusterName the name of the cluster the action is meant for
+   * @paran originalStackId the stack Id of the cluster before the upgrade.
+   * @paran targetStackId the stack Id that was desired for this upgrade.
+   * @return the command report to return
+   */
+  private CommandReport updateDesiredStack(String clusterName, StackId originalStackId, StackId targetStackId)
+      throws AmbariException, InterruptedException {
+    StringBuilder out = new StringBuilder();
+    StringBuilder err = new StringBuilder();
+
+    try {
+      Cluster cluster = clusters.getCluster(clusterName);
+      StackId currentClusterStackId = cluster.getCurrentStackVersion();
+
+      out.append(String.format("Checking if can update the Desired Stack Id to %s. The cluster's current Stack Id is %s\n", targetStackId.getStackId(), currentClusterStackId.getStackId()));
+
+      // Ensure that the target stack id exist
+      StackInfo desiredClusterStackInfo = ambariMetaInfo.getStack(targetStackId.getStackName(), targetStackId.getStackVersion());
+      if (null == desiredClusterStackInfo) {
+        String message = String.format("Parameter %s has an invalid value: %s. That Stack Id does not exist.\n",
+            TARGET_STACK_KEY, targetStackId.getStackId());
+        err.append(message);
+        out.append(message);
+        return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString());
+      }
+
+      // Ensure that the current Stack Id coincides with the parameter that the user passed in.
+      if (!currentClusterStackId.equals(originalStackId)) {
+        String message = String.format("Parameter %s has invalid value: %s. " +
+            "The cluster is currently on stack %s, " + currentClusterStackId.getStackId() +
+            ", yet the parameter to this function indicates a different value.\n", ORIGINAL_STACK_KEY, targetStackId.getStackId(), currentClusterStackId.getStackId());
+        err.append(message);
+        out.append(message);
+        return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString());
+      }
+
+      // Check for a no-op
+      if (currentClusterStackId.equals(targetStackId)) {
+        String message = String.format("Success! The cluster's Desired Stack Id was already set to %s\n", targetStackId.getStackId());
+        out.append(message);
+        return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", out.toString(), err.toString());
+      }
+
+      cluster.setDesiredStackVersion(targetStackId, true);
+      String message = String.format("Success! Set cluster's %s Desired Stack Id to %s.\n", clusterName, targetStackId.getStackId());
+      out.append(message);
+
+      return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", out.toString(), err.toString());
+    } catch (Exception e) {
+      StringWriter sw = new StringWriter();
+      e.printStackTrace(new PrintWriter(sw));
+      err.append(sw.toString());
+
+      return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
index d86210a..b1077f7 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
@@ -42,6 +42,14 @@ public class UpgradeContext {
   private StackId m_originalStackId;
 
   /**
+   * The stack currently used to start/restart services during an upgrade.This is the same
+   * During a {@link UpgradeType#ROLLING} upgrade, this is always the {@link this.m_targetStackId},
+   * During a {@link UpgradeType#NON_ROLLING} upgrade, this is initially the {@link this.m_sourceStackId} while
+   * stopping services, and then changes to the {@link this.m_targetStackId} when starting services.
+   */
+  private StackId m_effectiveStackId;
+
+  /**
    * The target upgrade stack before the upgrade started. This is the same
    * regardless of whether the current direction is {@link Direction#UPGRADE} or
    * {@link Direction#DOWNGRADE}.
@@ -84,6 +92,19 @@ public class UpgradeContext {
       Direction direction, UpgradeType type) {
     m_version = version;
     m_originalStackId = sourceStackId;
+
+    switch (type) {
+      case ROLLING:
+        m_effectiveStackId = targetStackId;
+        break;
+      case NON_ROLLING:
+        m_effectiveStackId = sourceStackId;
+        break;
+      default:
+        m_effectiveStackId = targetStackId;
+        break;
+    }
+
     m_targetStackId = targetStackId;
     m_direction = direction;
     m_resolver = resolver;
@@ -162,6 +183,21 @@ public class UpgradeContext {
   }
 
   /**
+   * @return the effectiveStackId that is currently in use.
+   */
+  public StackId getEffectiveStackId() {
+    return m_effectiveStackId;
+  }
+
+  /**
+   * @param effectiveStackId the effectiveStackId to set
+   */
+  public void setEffectiveStackId(StackId effectiveStackId) {
+    m_effectiveStackId = effectiveStackId;
+  }
+
+
+  /**
    * @return the targetStackId
    */
   public StackId getTargetStackId() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
index 442c9ed..3acee63 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
@@ -207,6 +207,7 @@ public class UpgradeHelper {
       UpgradeGroupHolder groupHolder = new UpgradeGroupHolder();
       groupHolder.name = group.name;
       groupHolder.title = group.title;
+      groupHolder.groupClass = group.getClass();
       groupHolder.skippable = group.skippable;
       groupHolder.allowRetry = group.allowRetry;
 
@@ -481,6 +482,9 @@ public class UpgradeHelper {
      */
     public String title;
 
+
+    public Class<? extends Grouping> groupClass;
+
     /**
      * Indicate whether retry is allowed for the stages in this group.
      */

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
----------------------------------------------------------------------
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 ec0fabf..36a0194 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
@@ -36,7 +36,7 @@ import org.apache.commons.lang.StringUtils;
 /**
  *
  */
-@XmlSeeAlso(value = { ColocatedGrouping.class, ClusterGrouping.class, ServiceCheckGrouping.class, RestartGrouping.class, StartGrouping.class, StopGrouping.class })
+@XmlSeeAlso(value = { ColocatedGrouping.class, ClusterGrouping.class, UpdateStackGrouping.class, ServiceCheckGrouping.class, RestartGrouping.class, StartGrouping.class, StopGrouping.class })
 public class Grouping {
 
   @XmlAttribute(name="name")

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
index ea59d65..5f6438c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
@@ -17,8 +17,6 @@
  */
 package org.apache.ambari.server.state.stack.upgrade;
 
-import org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction;
-
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
new file mode 100644
index 0000000..9dc9af8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
@@ -0,0 +1,36 @@
+/**
+ * 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.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Used to represent operations that update the Stack.
+ * This is primarily needed during a {@link UpgradeType#NON_ROLLING} upgrade.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="update-stack")
+public class UpdateStackGrouping extends ClusterGrouping {
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/resources/stacks/HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml b/ambari-server/src/main/resources/stacks/HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml
index c55e1a8..743204c0 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/upgrades/nonrolling-upgrade-2.3.xml
@@ -171,6 +171,14 @@
       </execute-stage>
     </group>
 
+    <!-- After processing this group, will change the effective Stack of the UpgradeContext object. -->
+    <group xsi:type="update-stack" name="UPDATE_DESIRED_STACK_ID" title="Update Desired Stack Id">
+      <execute-stage title="Update Desired Stack Id" service="" component="">
+        <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction">
+        </task>
+      </execute-stage>
+    </group>
+
     <group xsi:type="cluster" name="ALL_HOST_OPS" title="Set Version On All Hosts">
       <skippable>true</skippable>
       <execute-stage title="Update stack to {{version}}">

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml
index 01022b8..e95aabc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/nonrolling-upgrade-2.2.xml
@@ -217,6 +217,14 @@
       </execute-stage>
     </group>
 
+    <!-- After processing this group, will change the effective Stack of the UpgradeContext object. -->
+    <group xsi:type="update-stack" name="UPDATE_DESIRED_STACK_ID" title="Update Desired Stack Id">
+      <execute-stage title="Update Desired Stack Id" service="" component="">
+        <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction">
+        </task>
+      </execute-stage>
+    </group>
+
     <group xsi:type="cluster" name="ALL_HOST_OPS" title="Set Version On All Hosts">
       <skippable>true</skippable>
       <execute-stage title="Update stack to {{version}}">

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
index 6708422..1c4fe76 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
@@ -883,7 +883,7 @@ public class UpgradeResourceProviderTest {
 
     Map<String, UpgradePack> upgradePacks = ambariMetaInfo.getUpgradePacks("HDP", "2.1.1");
     UpgradePack upgrade = upgradePacks.get("upgrade_to_new_stack");
-    upgradeResourceProvider.processConfigurations(stack211.getStackName(), cluster, "2.2.0.0", Direction.UPGRADE, upgrade);
+    upgradeResourceProvider.applyStackAndProcessConfigurations(stack211.getStackName(), cluster, "2.2.0.0", Direction.UPGRADE, upgrade);
 
     Map<String, Map<String, String>> expectedConfigurations = expectedConfigurationsCapture.getValue();
     Map<String, String> expectedFooType = expectedConfigurations.get("foo-site");

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
index b746bc1..cfeb08c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
@@ -43,6 +43,7 @@ import org.apache.ambari.server.state.stack.upgrade.RestartTask;
 import org.apache.ambari.server.state.stack.upgrade.StopGrouping;
 import org.apache.ambari.server.state.stack.upgrade.Task;
 import org.apache.ambari.server.state.stack.upgrade.TransferOperation;
+import org.apache.ambari.server.state.stack.upgrade.UpdateStackGrouping;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 import org.junit.After;
 import org.junit.Before;
@@ -245,6 +246,7 @@ public class UpgradePackTest {
         "Stop High-Level Daemons",
         "Backups",
         "Stop Low-Level Daemons",
+        "UPDATE_DESIRED_STACK_ID",
         "ALL_HOST_OPS",
         "ZOOKEEPER",
         "HDFS",
@@ -302,10 +304,11 @@ public class UpgradePackTest {
     assertTrue(upgrade.getType() == UpgradeType.NON_ROLLING);
 
     List<Grouping> groups = upgrade.getGroups(Direction.UPGRADE);
-    assertEquals(9, groups.size());
+    assertEquals(10, groups.size());
 
     Grouping group = null;
     ClusterGrouping clusterGroup = null;
+    UpdateStackGrouping updateStackGroup = null;
     StopGrouping stopGroup = null;
     RestartGrouping restartGroup = null;
 
@@ -330,26 +333,31 @@ public class UpgradePackTest {
     assertEquals("Stop Daemons for Low-Level Services", stopGroup.title);
 
     group = groups.get(4);
+    assertEquals(UpdateStackGrouping.class, group.getClass());
+    updateStackGroup = (UpdateStackGrouping) group;
+    assertEquals("Update Desired Stack Id", updateStackGroup.title);
+
+    group = groups.get(5);
     assertEquals(ClusterGrouping.class, group.getClass());
     clusterGroup = (ClusterGrouping) group;
     assertEquals("Set Version On All Hosts", clusterGroup.title);
 
-    group = groups.get(5);
+    group = groups.get(6);
     assertEquals(RestartGrouping.class, group.getClass());
     restartGroup = (RestartGrouping) group;
     assertEquals("Zookeeper", restartGroup.title);
 
-    group = groups.get(6);
+    group = groups.get(7);
     assertEquals(RestartGrouping.class, group.getClass());
     restartGroup = (RestartGrouping) group;
     assertEquals("HDFS", restartGroup.title);
 
-    group = groups.get(7);
+    group = groups.get(8);
     assertEquals(RestartGrouping.class, group.getClass());
     restartGroup = (RestartGrouping) group;
     assertEquals("MR and YARN", restartGroup.title);
 
-    group = groups.get(8);
+    group = groups.get(9);
     assertEquals(ClusterGrouping.class, group.getClass());
     clusterGroup = (ClusterGrouping) group;
     assertEquals("Finalize {{direction.text.proper}}", clusterGroup.title);

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog212Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog212Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog212Test.java
index 1f27cb3..9701604 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog212Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog212Test.java
@@ -206,6 +206,7 @@ public class UpgradeCatalog212Test {
     // Repository Version
     RepositoryVersionEntity repositoryVersionEntity = createNiceMock(RepositoryVersionEntity.class);
     expect(repositoryVersionDAO.findByDisplayName(stackAndBuild)).andReturn(null);
+    expect(repositoryVersionDAO.findMaxId("id")).andReturn(0L);
     expect(repositoryVersionDAO.findAll()).andReturn(Collections.<RepositoryVersionEntity>emptyList());
     expect(repositoryVersionDAO.create(anyObject(StackEntity.class), anyObject(String.class), anyObject(String.class), anyObject(String.class))).andReturn(repositoryVersionEntity);
     expect(repositoryVersionEntity.getId()).andReturn(1L);
@@ -219,6 +220,7 @@ public class UpgradeCatalog212Test {
     expect(clusterVersionEntity.getRepositoryVersion()).andReturn(repositoryVersionEntity);
 
     expect(clusterVersionDAO.findByClusterAndStackAndVersion(anyObject(String.class), anyObject(StackId.class), anyObject(String.class))).andReturn(null);
+    expect(clusterVersionDAO.findMaxId("id")).andReturn(0L);
     expect(clusterVersionDAO.findAll()).andReturn(Collections.<ClusterVersionEntity>emptyList());
     expect(clusterVersionDAO.create(anyObject(ClusterEntity.class), anyObject(RepositoryVersionEntity.class), anyObject(RepositoryVersionState.class), anyLong(), anyLong(), anyObject(String.class))).andReturn(clusterVersionEntity);
     replay(clusterVersionDAO, clusterVersionEntity);
@@ -238,6 +240,7 @@ public class UpgradeCatalog212Test {
     expect(clusterEntity.getHostEntities()).andReturn(hostEntities);
 
     expect(hostVersionDAO.findByClusterStackVersionAndHost(anyObject(String.class), anyObject(StackId.class), anyObject(String.class), anyObject(String.class))).andReturn(null);
+    expect(hostVersionDAO.findMaxId("id")).andReturn(0L);
     expect(hostVersionDAO.findAll()).andReturn(Collections.<HostVersionEntity>emptyList());
 
     replay(clusterEntity, clusterDAO, hostVersionDAO, hostEntity1, hostEntity2);

http://git-wip-us.apache.org/repos/asf/ambari/blob/247e728c/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test_nonrolling.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test_nonrolling.xml b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test_nonrolling.xml
index 13c5d1f..73b6834 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test_nonrolling.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test_nonrolling.xml
@@ -89,6 +89,14 @@
       </execute-stage>
     </group>
 
+    <!-- After processing this group, will change the effective Stack of the UpgradeContext object. -->
+    <group xsi:type="update-stack" name="UPDATE_DESIRED_STACK_ID" title="Update Desired Stack Id">
+      <execute-stage title="Update Desired Stack Id" service="" component="">
+        <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction">
+        </task>
+      </execute-stage>
+    </group>
+
     <group xsi:type="cluster" name="ALL_HOST_OPS" title="Set Version On All Hosts">
       <skippable>true</skippable>
       <execute-stage title="Update stack to {{version}}">