http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/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 e9ac429..6fe074d 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
@@ -78,6 +78,7 @@ import 
org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.stack.MasterHostResolver;
 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.ConfigHelper;
 import org.apache.ambari.server.state.DesiredConfig;
@@ -87,6 +88,7 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeHelper;
 import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
@@ -97,6 +99,8 @@ 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;
 import org.slf4j.Logger;
@@ -114,6 +118,8 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
 
   protected static final String UPGRADE_CLUSTER_NAME = "Upgrade/cluster_name";
   protected static final String UPGRADE_VERSION = "Upgrade/repository_version";
+  protected static final String UPGRADE_TYPE = "Upgrade/type";
+  protected static final String UPGRADE_PACK = "Upgrade/pack";
   protected static final String UPGRADE_REQUEST_ID = "Upgrade/request_id";
   protected static final String UPGRADE_FROM_VERSION = "Upgrade/from_version";
   protected static final String UPGRADE_TO_VERSION = "Upgrade/to_version";
@@ -153,6 +159,8 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
   private static final String COMMAND_PARAM_VERSION = VERSION;
   private static final String COMMAND_PARAM_CLUSTER_NAME = "clusterName";
   private static final String COMMAND_PARAM_DIRECTION = "upgrade_direction";
+  // TODO AMBARI-12698, change this variable name since it is no longer always 
a restart. Possible values are rolling_upgrade or nonrolling_upgrade
+  // This will involve changing Script.py
   private static final String COMMAND_PARAM_RESTART_TYPE = "restart_type";
   private static final String COMMAND_PARAM_TASKS = "tasks";
   private static final String COMMAND_PARAM_STRUCT_OUT = "structured_out";
@@ -192,6 +200,9 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
   private static Provider<StageFactory> s_stageFactory;
 
   @Inject
+  private static Provider<Clusters> clusters = null;
+
+  @Inject
   private static Provider<AmbariActionExecutionHelper> s_actionExecutionHelper;
 
   @Inject
@@ -216,6 +227,8 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     // properties
     PROPERTY_IDS.add(UPGRADE_CLUSTER_NAME);
     PROPERTY_IDS.add(UPGRADE_VERSION);
+    PROPERTY_IDS.add(UPGRADE_TYPE);
+    PROPERTY_IDS.add(UPGRADE_PACK);
     PROPERTY_IDS.add(UPGRADE_REQUEST_ID);
     PROPERTY_IDS.add(UPGRADE_FROM_VERSION);
     PROPERTY_IDS.add(UPGRADE_TO_VERSION);
@@ -437,6 +450,8 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     ResourceImpl resource = new ResourceImpl(Resource.Type.Upgrade);
 
     setResourceProperty(resource, UPGRADE_CLUSTER_NAME, clusterName, 
requestedIds);
+    setResourceProperty(resource, UPGRADE_TYPE, 
entity.getUpgradeType().toString(), requestedIds);
+    setResourceProperty(resource, UPGRADE_PACK, entity.getUpgradePackage(), 
requestedIds);
     setResourceProperty(resource, UPGRADE_REQUEST_ID, entity.getRequestId(), 
requestedIds);
     setResourceProperty(resource, UPGRADE_FROM_VERSION, 
entity.getFromVersion(), requestedIds);
     setResourceProperty(resource, UPGRADE_TO_VERSION, entity.getToVersion(), 
requestedIds);
@@ -458,8 +473,10 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);
     String version = (String) requestMap.get(UPGRADE_VERSION);
     String versionForUpgradePack = (String) 
requestMap.get(UPGRADE_FROM_VERSION);
-    boolean skipPrereqChecks = Boolean.parseBoolean((String) 
requestMap.get(UPGRADE_SKIP_PREREQUISITE_CHECKS));
-    boolean failOnCheckWarnings = Boolean.parseBoolean((String) 
requestMap.get(UPGRADE_FAIL_ON_CHECK_WARNINGS));
+
+    // Default to ROLLING upgrade, but attempt to read from properties.
+    final UpgradeType upgradeType = requestMap.containsKey(UPGRADE_TYPE) ?
+        UpgradeType.valueOf((String) requestMap.get(UPGRADE_TYPE)) : 
UpgradeType.ROLLING;
 
     if (null == clusterName) {
       throw new AmbariException(String.format("%s is required", 
UPGRADE_CLUSTER_NAME));
@@ -469,60 +486,41 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
       throw new AmbariException(String.format("%s is required", 
UPGRADE_VERSION));
     }
 
-    Cluster cluster = 
getManagementController().getClusters().getCluster(clusterName);
-
-    // !!! find upgrade packs based on current stack. This is where to upgrade
-    // from.
-    StackId stack = cluster.getCurrentStackVersion();
-
-    String repoVersion = version;
-
-    if (direction.isDowngrade() && null != versionForUpgradePack) {
-      repoVersion = versionForUpgradePack;
-    }
-
-    RepositoryVersionEntity versionEntity = 
s_repoVersionDAO.findByStackNameAndVersion(stack.getStackName(), repoVersion);
-
-    if (null == versionEntity) {
-      throw new AmbariException(String.format("Repository version %s was not 
found", repoVersion));
-    }
-
-    Map<String, UpgradePack> packs = 
s_metaProvider.get().getUpgradePacks(stack.getStackName(),
-        stack.getStackVersion());
+    // Do not insert here additional checks! Wrap them to separate functions.
+    // Pre-req checks, function generate exceptions if something going wrong
+    validatePreRequest(clusterName, direction, version, requestMap);
 
-    UpgradePack up = packs.get(versionEntity.getUpgradePackage());
+    return s_upgradeHelper.suggestUpgradePack(clusterName, 
versionForUpgradePack, version, direction, upgradeType);
+  }
 
-    if (null == up) {
-      // !!! in case there is an upgrade pack that doesn't match the name
-      String repoStackId = versionEntity.getStackId().getStackId();
-      for (UpgradePack upgradePack : packs.values()) {
-        if (null != upgradePack.getTargetStack()
-            && upgradePack.getTargetStack().equals(repoStackId)) {
-          up = upgradePack;
-          break;
-        }
-      }
-    }
+  /**
+   * Pre-req checks
+   * @param clusterName Name of the cluster
+   * @param direction Direction of upgrade
+   * @param repoVersion target repository version
+   * @param requestMap request arguments
+   * @throws AmbariException
+   */
+  private void validatePreRequest(String clusterName, Direction direction, 
String repoVersion, Map<String, Object> requestMap)
+    throws AmbariException{
 
-    if (null == up) {
-      throw new AmbariException(
-          String.format("Unable to perform %s.  Could not locate upgrade pack 
%s for version %s",
-              direction.getText(false), versionEntity.getUpgradePackage(), 
repoVersion));
-    }
+    Cluster cluster = clusters.get().getCluster(clusterName);
+    boolean skipPrereqChecks = Boolean.parseBoolean((String) 
requestMap.get(UPGRADE_SKIP_PREREQUISITE_CHECKS));
+    boolean failOnCheckWarnings = Boolean.parseBoolean((String) 
requestMap.get(UPGRADE_FAIL_ON_CHECK_WARNINGS));
 
     // Validate there isn't an direction == upgrade/downgrade already in 
progress.
     List<UpgradeEntity> upgrades = 
s_upgradeDAO.findUpgrades(cluster.getClusterId());
     for (UpgradeEntity entity : upgrades) {
       if(entity.getDirection() == direction) {
         Map<Long, HostRoleCommandStatusSummaryDTO> summary = 
s_hostRoleCommandDAO.findAggregateCounts(
-            entity.getRequestId());
+          entity.getRequestId());
         CalculatedStatus calc = 
CalculatedStatus.statusFromStageSummary(summary, summary.keySet());
         HostRoleStatus status = calc.getStatus();
         if(!HostRoleStatus.getCompletedStates().contains(status)) {
           throw new AmbariException(
-              String.format("Unable to perform %s as another %s is in 
progress. %s %d is in %s",
-                  direction.getText(false), direction.getText(false), 
direction.getText(true),
-                  entity.getRequestId().longValue(), status)
+            String.format("Unable to perform %s as another %s is in progress. 
%s %d is in %s",
+              direction.getText(false), direction.getText(false), 
direction.getText(true),
+              entity.getRequestId().longValue(), status)
           );
         }
       }
@@ -531,29 +529,29 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     if(direction.isUpgrade() && !skipPrereqChecks) {
       // Validate pre-req checks pass
       PreUpgradeCheckResourceProvider preUpgradeCheckResourceProvider = 
(PreUpgradeCheckResourceProvider)
-          getResourceProvider(Resource.Type.PreUpgradeCheck);
+        getResourceProvider(Resource.Type.PreUpgradeCheck);
       Predicate preUpgradeCheckPredicate = new PredicateBuilder().property(
-          
PreUpgradeCheckResourceProvider.UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).equals(clusterName).and().property(
-          
PreUpgradeCheckResourceProvider.UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).equals(repoVersion).toPredicate();
+        
PreUpgradeCheckResourceProvider.UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).equals(clusterName).and().property(
+        
PreUpgradeCheckResourceProvider.UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).equals(repoVersion).toPredicate();
       Request preUpgradeCheckRequest = PropertyHelper.getReadRequest();
 
       Set<Resource> preUpgradeCheckResources;
       try {
         preUpgradeCheckResources = 
preUpgradeCheckResourceProvider.getResources(
-            preUpgradeCheckRequest, preUpgradeCheckPredicate);
-      } catch (NoSuchResourceException e) {
+          preUpgradeCheckRequest, preUpgradeCheckPredicate);
+      } catch 
(NoSuchResourceException|SystemException|UnsupportedPropertyException|NoSuchParentResourceException
 e) {
         throw new AmbariException(
-            String.format("Unable to perform %s. Prerequisite checks could not 
be run",
-                direction.getText(false)));
+          String.format("Unable to perform %s. Prerequisite checks could not 
be run",
+            direction.getText(false)));
       }
       List<Resource> failedResources = new LinkedList<Resource>();
       if (preUpgradeCheckResources != null) {
         for(Resource res : preUpgradeCheckResources) {
           String id = (String) 
res.getPropertyValue((PreUpgradeCheckResourceProvider.UPGRADE_CHECK_ID_PROPERTY_ID));
           PrereqCheckStatus prereqCheckStatus = (PrereqCheckStatus) 
res.getPropertyValue(
-              
PreUpgradeCheckResourceProvider.UPGRADE_CHECK_STATUS_PROPERTY_ID);
+            PreUpgradeCheckResourceProvider.UPGRADE_CHECK_STATUS_PROPERTY_ID);
           if(prereqCheckStatus == PrereqCheckStatus.FAIL
-              || (failOnCheckWarnings && prereqCheckStatus == 
PrereqCheckStatus.WARNING)) {
+            || (failOnCheckWarnings && prereqCheckStatus == 
PrereqCheckStatus.WARNING)) {
             failedResources.add(res);
           }
         }
@@ -561,12 +559,10 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
       if(!failedResources.isEmpty()) {
         Gson gson = new Gson();
         throw new AmbariException(
-            String.format("Unable to perform %s. Prerequisite checks failed 
%s",
-                direction.getText(false), gson.toJson(failedResources)));
+          String.format("Unable to perform %s. Prerequisite checks failed %s",
+            direction.getText(false), gson.toJson(failedResources)));
       }
     }
-
-    return up;
   }
 
   /**
@@ -642,7 +638,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     }
 
     UpgradeContext ctx = new UpgradeContext(resolver, sourceStackId, 
targetStackId, version,
-        direction);
+        direction, pack.getType());
 
     if (direction.isDowngrade()) {
       if (requestMap.containsKey(UPGRADE_FROM_VERSION)) {
@@ -682,9 +678,39 @@ 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);
+    }
+
+    // Resolve or build a proper config upgrade pack
+    List<UpgradePack.IntermediateStack> intermediateStacks = 
pack.getIntermediateStacks();
+    ConfigUpgradePack configUpgradePack;
+    if (intermediateStacks == null || intermediateStacks.isEmpty()) { // No 
intermediate stacks
+      configUpgradePack = s_metaProvider.get().getConfigUpgradePack(
+              targetStackId.getStackName(), targetStackId.getStackVersion());
+    } else {
+      // For cross-stack upgrade, follow all major stacks and merge a new 
config upgrade pack from all
+      // target stacks involved into upgrade
+      ArrayList<ConfigUpgradePack> intermediateConfigUpgradePacks = new 
ArrayList<>();
+      for (UpgradePack.IntermediateStack intermediateStack : 
intermediateStacks) {
+        ConfigUpgradePack intermediateConfigUpgradePack = 
s_metaProvider.get().getConfigUpgradePack(
+                targetStackId.getStackName(), intermediateStack.version);
+        intermediateConfigUpgradePacks.add(intermediateConfigUpgradePack);
+      }
+      configUpgradePack = 
ConfigUpgradePack.merge(intermediateConfigUpgradePacks);
+    }
 
     for (UpgradeGroupHolder group : groups) {
       UpgradeGroupEntity groupEntity = new UpgradeGroupEntity();
@@ -707,11 +733,17 @@ 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);
 
               makeServerSideStage(ctx, req, itemEntity, (ServerSideActionTask) 
task, skippable,
-                  allowRetry);
+                  allowRetry, configUpgradePack);
             }
           }
         } else {
@@ -736,8 +768,10 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     
entity.setFromVersion(cluster.getCurrentClusterVersion().getRepositoryVersion().getVersion());
     entity.setToVersion(version);
     entity.setUpgradeGroups(groupEntities);
-    entity.setClusterId(Long.valueOf(cluster.getClusterId()));
+    entity.setClusterId(cluster.getClusterId());
     entity.setDirection(direction);
+    entity.setUpgradePackage(pack.getName());
+    entity.setUpgradeType(pack.getType());
 
     req.getRequestStatusResponse();
 
@@ -784,7 +818,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) {
@@ -816,6 +850,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     Map<String, Map<String, String>> newConfigurationsByType = null;
     ConfigHelper configHelper = getManagementController().getConfigHelper();
 
+    // TODO AMBARI-12698, handle jumping across several stacks
     if (direction == Direction.UPGRADE) {
       // populate a map of default configurations for the old stack (this is
       // used when determining if a property has been customized and should be
@@ -884,7 +919,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) {
@@ -971,8 +1006,10 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
           throws AmbariException {
 
     switch (wrapper.getType()) {
+      case START:
+      case STOP:
       case RESTART:
-        makeRestartStage(context, request, entity, wrapper, skippable, 
allowRetry);
+        makeCommandStage(context, request, entity, wrapper, skippable, 
allowRetry);
         break;
       case RU_TASKS:
         makeActionStage(context, request, entity, wrapper, skippable, 
allowRetry);
@@ -1012,7 +1049,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());
@@ -1035,7 +1072,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped());
 
     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(),
@@ -1064,7 +1101,17 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     request.addStages(Collections.singletonList(stage));
   }
 
-  private void makeRestartStage(UpgradeContext context, RequestStageContainer 
request,
+  /**
+   * 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
+   * @throws AmbariException
+   */
+  private void makeCommandStage(UpgradeContext context, RequestStageContainer 
request,
       UpgradeItemEntity entity, StageWrapper wrapper, boolean skippable, 
boolean allowRetry)
           throws AmbariException {
 
@@ -1078,23 +1125,43 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
           new ArrayList<String>(tw.getHosts())));
     }
 
-    Map<String, String> restartCommandParams = getNewParameterMap();
-    restartCommandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade");
-    restartCommandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
-    restartCommandParams.put(COMMAND_PARAM_DIRECTION, 
context.getDirection().name().toLowerCase());
-    
restartCommandParams.put(COMMAND_PARAM_ORIGINAL_STACK,context.getOriginalStackId().getStackId());
-    restartCommandParams.put(COMMAND_PARAM_TARGET_STACK, 
context.getTargetStackId().getStackId());
-    restartCommandParams.put(COMMAND_DOWNGRADE_FROM_VERSION, 
context.getDowngradeFromVersion());
+    String function = null;
+    switch (wrapper.getType()) {
+      case START:
+      case STOP:
+      case RESTART:
+        function = wrapper.getType().name();
+        break;
+      default:
+        function = "UNKNOWN";
+        break;
+    }
+
+    Map<String, String> commandParams = getNewParameterMap();
+
+    // TODO AMBARI-12698, change COMMAND_PARAM_RESTART_TYPE to something that 
isn't "RESTART" specific.
+    if (context.getType() == UpgradeType.ROLLING) {
+      commandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade");
+    }
+    if (context.getType() == UpgradeType.NON_ROLLING) {
+      commandParams.put(COMMAND_PARAM_RESTART_TYPE, "nonrolling_upgrade");
+    }
+
+    commandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
+    commandParams.put(COMMAND_PARAM_DIRECTION, 
context.getDirection().name().toLowerCase());
+    commandParams.put(COMMAND_PARAM_ORIGINAL_STACK, 
context.getOriginalStackId().getStackId());
+    commandParams.put(COMMAND_PARAM_TARGET_STACK, 
context.getTargetStackId().getStackId());
+    commandParams.put(COMMAND_DOWNGRADE_FROM_VERSION, 
context.getDowngradeFromVersion());
 
     ActionExecutionContext actionContext = new 
ActionExecutionContext(cluster.getClusterName(),
-        "RESTART", filters, restartCommandParams);
+        function, filters, commandParams);
     
actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false)));
     actionContext.setIgnoreMaintenance(true);
     actionContext.setRetryAllowed(allowRetry);
     actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped());
 
     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(),
@@ -1112,7 +1179,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     entity.setStageId(Long.valueOf(stageId));
 
     Map<String, String> requestParams = new HashMap<String, String>();
-    requestParams.put("command", "RESTART");
+    requestParams.put("command", function);
 
     s_commandExecutionHelper.get().addExecutionCommandsToStage(actionContext, 
stage, requestParams);
 
@@ -1147,7 +1214,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     
actionContext.setAutoSkipFailures(context.isServiceCheckFailureAutoSkipped());
 
     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(),
@@ -1170,8 +1237,22 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     request.addStages(Collections.singletonList(stage));
   }
 
+  /**
+   * Creates a stage consisting of server side actions
+   * @param context upgrade context
+   * @param request upgrade request
+   * @param entity a single of upgrade
+   * @param task server-side task (if any)
+   * @param skippable if user can skip stage on failure
+   * @param allowRetry if user can retry running stage on failure
+   * @param configUpgradePack a runtime-generated config upgrade pack that
+   * contains all config change definitions from all stacks involved into
+   * upgrade
+   * @throws AmbariException
+   */
   private void makeServerSideStage(UpgradeContext context, 
RequestStageContainer request,
-      UpgradeItemEntity entity, ServerSideActionTask task, boolean skippable, 
boolean allowRetry)
+      UpgradeItemEntity entity, ServerSideActionTask task, boolean skippable, 
boolean allowRetry,
+      ConfigUpgradePack configUpgradePack)
           throws AmbariException {
 
     Cluster cluster = context.getCluster();
@@ -1204,7 +1285,8 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
       }
       case CONFIGURE: {
         ConfigureTask ct = (ConfigureTask) task;
-        Map<String, String> configurationChanges = 
ct.getConfigurationChanges(cluster);
+        Map<String, String> configurationChanges =
+                ct.getConfigurationChanges(cluster, configUpgradePack);
 
         // add all configuration changes to the command params
         commandParams.putAll(configurationChanges);
@@ -1241,7 +1323,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped());
 
     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/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java
index e821827..f5642a0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java
@@ -58,8 +58,10 @@ public class ActionMetadata {
 
   private void fillHostComponentCommands() {
     //Standart commands for any host component
-    // TODO: Add START/STOP/INSTALL commands
     defaultHostComponentCommands.add("RESTART");
+    defaultHostComponentCommands.add("START");
+    defaultHostComponentCommands.add("STOP");
+    defaultHostComponentCommands.add("INSTALL");
     defaultHostComponentCommands.add("CONFIGURE");
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java
index d3326b1..8d4c5ee 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java
@@ -23,8 +23,11 @@ import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
 import javax.persistence.TypedQuery;
 
+import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.StackId;
 
@@ -153,4 +156,24 @@ public class ClusterVersionDAO extends 
CrudDAO<ClusterVersionEntity, Long>{
 
     return daoUtils.selectList(query);
   }
+
+  /**
+   * Construct a Cluster Version and return it. This is primarily used to be 
able to construct the object and mock
+   * the function call.
+   * @param cluster Cluster
+   * @param repositoryVersion Repository Version
+   * @param state Initial State
+   * @param startTime Start Time
+   * @param endTime End Time
+   * @param userName Username, such as "admin"
+   * @return Return new ClusterVersion object.
+   */
+  @Transactional
+  public ClusterVersionEntity create(ClusterEntity cluster, 
RepositoryVersionEntity repositoryVersion,
+                                     RepositoryVersionState state, long 
startTime, long endTime, String userName) {
+    ClusterVersionEntity clusterVersionEntity = new 
ClusterVersionEntity(cluster,
+        repositoryVersion, state, startTime, endTime, userName);
+    this.create(clusterVersionEntity);
+    return clusterVersionEntity;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java
index 4382f59..ed0a931 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java
@@ -73,6 +73,21 @@ public class CrudDAO<E, K> {
   }
 
   /**
+   * Retrieves the maximum ID from the entities.
+   *
+   * @param idColName name of the column that corresponds to the ID.
+   * @return maximum ID, or 0 if none exist.
+   */
+  @RequiresSession
+  public Long findMaxId(String idColName) {
+    final TypedQuery<Long> query = 
entityManagerProvider.get().createQuery("SELECT MAX(entity." + idColName + ") 
FROM "
+        + entityClass.getSimpleName() + " entity", Long.class);
+    // May be null if no results.
+    Long result = daoUtils.selectOne(query);
+    return result == null ? 0 : result;
+  }
+
+  /**
    * Creates entity.
    *
    * @param entity entity to create

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
index a2ff211..ad617af 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
@@ -43,21 +43,17 @@ import com.google.inject.persist.Transactional;
  * {@link org.apache.ambari.server.state.RepositoryVersionState#UPGRADING}.
  */
 @Singleton
-public class HostVersionDAO {
+public class HostVersionDAO extends CrudDAO<HostVersionEntity, Long> {
   @Inject
   Provider<EntityManager> entityManagerProvider;
   @Inject
   DaoUtils daoUtils;
 
   /**
-   * Get the object with the given id.
-   *
-   * @param id Primary key id
-   * @return Return the object with the given primary key
+   * Constructor.
    */
-  @RequiresSession
-  public HostVersionEntity findByPK(long id) {
-    return entityManagerProvider.get().find(HostVersionEntity.class, id);
+  public HostVersionDAO() {
+    super(HostVersionEntity.class);
   }
 
   /**
@@ -189,31 +185,6 @@ public class HostVersionDAO {
     return daoUtils.selectSingle(query);
   }
 
-  @RequiresSession
-  public List<HostVersionEntity> findAll() {
-    return daoUtils.selectAll(entityManagerProvider.get(), 
HostVersionEntity.class);
-  }
-
-  @Transactional
-  public void refresh(HostVersionEntity hostVersionEntity) {
-    entityManagerProvider.get().refresh(hostVersionEntity);
-  }
-
-  @Transactional
-  public void create(HostVersionEntity hostVersionEntity) {
-    entityManagerProvider.get().persist(hostVersionEntity);
-  }
-
-  @Transactional
-  public HostVersionEntity merge(HostVersionEntity hostVersionEntity) {
-    return entityManagerProvider.get().merge(hostVersionEntity);
-  }
-
-  @Transactional
-  public void remove(HostVersionEntity hostVersionEntity) {
-    entityManagerProvider.get().remove(merge(hostVersionEntity));
-  }
-
   @Transactional
   public void removeByHostName(String hostName) {
     Collection<HostVersionEntity> hostVersions = this.findByHost(hostName);
@@ -221,9 +192,4 @@ public class HostVersionDAO {
       this.remove(hostVersion);
     }
   }
-
-  @Transactional
-  public void removeByPK(long id) {
-    remove(findByPK(id));
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
index 4ac1314..9f5f6f1 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
@@ -129,15 +129,13 @@ public class RepositoryVersionDAO extends 
CrudDAO<RepositoryVersionEntity, Long>
    * @param stackEntity Stack entity.
    * @param version Stack version, e.g., 2.2 or 2.2.0.1-885
    * @param displayName Unique display name
-   * @param upgradePack Optional upgrade pack, e.g, upgrade-2.2
    * @param operatingSystems JSON structure of repository URLs for each OS
    * @return Returns the object created if successful, and throws an exception 
otherwise.
    * @throws AmbariException
    */
   @Transactional
   public RepositoryVersionEntity create(StackEntity stackEntity,
-      String version, String displayName, String upgradePack,
-      String operatingSystems) throws AmbariException {
+      String version, String displayName, String operatingSystems) throws 
AmbariException {
 
     if (stackEntity == null || version == null || version.isEmpty()
         || displayName == null || displayName.isEmpty()) {
@@ -164,7 +162,7 @@ public class RepositoryVersionDAO extends 
CrudDAO<RepositoryVersionEntity, Long>
     }
 
     RepositoryVersionEntity newEntity = new RepositoryVersionEntity(
-        stackEntity, version, displayName, upgradePack, operatingSystems);
+        stackEntity, version, displayName, operatingSystems);
     this.create(newEntity);
     return newEntity;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java
index bc0652c..06f6ac1 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java
@@ -48,6 +48,18 @@ public class UpgradeDAO {
   private DaoUtils daoUtils;
 
   /**
+   * Get all items.
+   * @return List of all of the UpgradeEntity items.
+   */
+  @RequiresSession
+  public List<UpgradeEntity> findAll() {
+    TypedQuery<UpgradeEntity> query = 
entityManagerProvider.get().createNamedQuery(
+        "UpgradeEntity.findAll", UpgradeEntity.class);
+
+    return daoUtils.selectList(query);
+  }
+
+  /**
    * @param clusterId the cluster id
    * @return the list of upgrades initiated for the cluster
    */
@@ -157,8 +169,7 @@ public class UpgradeDAO {
   }
 
   /**
-   * @param requestId the request id
-   * @param stageId the stage id
+   * @param clusterId the cluster id
    * @return the upgrade entity, or {@code null} if not found
    */
   @RequiresSession
@@ -174,4 +185,8 @@ public class UpgradeDAO {
     return daoUtils.selectSingle(query);
   }
 
+  @Transactional
+  public UpgradeEntity merge(UpgradeEntity upgradeEntity) {
+    return entityManagerProvider.get().merge(upgradeEntity);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
----------------------------------------------------------------------
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 dafd4b2..4296077 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
@@ -90,9 +90,6 @@ public class RepositoryVersionEntity {
   @Column(name = "display_name")
   private String displayName;
 
-  @Column(name = "upgrade_package")
-  private String upgradePackage;
-
   @Lob
   @Column(name = "repositories")
   private String operatingSystems;
@@ -110,11 +107,10 @@ public class RepositoryVersionEntity {
   }
 
   public RepositoryVersionEntity(StackEntity stack, String version,
-      String displayName, String upgradePackage, String operatingSystems) {
+      String displayName, String operatingSystems) {
     this.stack = stack;
     this.version = version;
     this.displayName = displayName;
-    this.upgradePackage = upgradePackage;
     this.operatingSystems = operatingSystems;
   }
 
@@ -161,14 +157,6 @@ public class RepositoryVersionEntity {
     this.displayName = displayName;
   }
 
-  public String getUpgradePackage() {
-    return upgradePackage;
-  }
-
-  public void setUpgradePackage(String upgradePackage) {
-    this.upgradePackage = upgradePackage;
-  }
-
   public String getOperatingSystemsJson() {
     return operatingSystems;
   }
@@ -233,9 +221,6 @@ public class RepositoryVersionEntity {
     if (displayName != null ? !displayName.equals(that.displayName) : 
that.displayName != null) {
       return false;
     }
-    if (upgradePackage != null ? !upgradePackage.equals(that.upgradePackage) : 
that.upgradePackage != null) {
-      return false;
-    }
     if (operatingSystems != null ? 
!operatingSystems.equals(that.operatingSystems) : that.operatingSystems != 
null) {
       return false;
     }
@@ -249,7 +234,6 @@ public class RepositoryVersionEntity {
     result = 31 * result + (stack != null ? stack.hashCode() : 0);
     result = 31 * result + (version != null ? version.hashCode() : 0);
     result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
-    result = 31 * result + (upgradePackage != null ? upgradePackage.hashCode() 
: 0);
     result = 31 * result + (operatingSystems != null ? 
operatingSystems.hashCode() : 0);
     return result;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java
index 802ea03..ad9073a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java
@@ -34,6 +34,7 @@ import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
 import org.apache.ambari.server.state.stack.upgrade.Direction;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 /**
  * Models the data representation of an upgrade
@@ -44,6 +45,8 @@ import org.apache.ambari.server.state.stack.upgrade.Direction;
     table = "ambari_sequences", pkColumnName = "sequence_name", 
valueColumnName = "sequence_value",
     pkColumnValue = "upgrade_id_seq", initialValue = 0)
 @NamedQueries({
+  @NamedQuery(name = "UpgradeEntity.findAll",
+      query = "SELECT u FROM UpgradeEntity u"),
   @NamedQuery(name = "UpgradeEntity.findAllForCluster",
       query = "SELECT u FROM UpgradeEntity u WHERE u.clusterId = :clusterId"),
   @NamedQuery(name = "UpgradeEntity.findUpgrade",
@@ -74,6 +77,13 @@ public class UpgradeEntity {
   @Enumerated(value = EnumType.STRING)
   private Direction direction = Direction.UPGRADE;
 
+  @Column(name="upgrade_package", nullable = false)
+  private String upgradePackage;
+
+  @Column(name="upgrade_type", nullable = false)
+  @Enumerated(value = EnumType.STRING)
+  private UpgradeType upgradeType;
+
   @OneToMany(mappedBy = "upgradeEntity", cascade = { CascadeType.ALL })
   private List<UpgradeGroupEntity> upgradeGroupEntities;
 
@@ -179,5 +189,84 @@ public class UpgradeEntity {
     this.direction = direction;
   }
 
+  /**
+   * @return the upgrade type, such as rolling or non_rolling
+   */
+  public UpgradeType getUpgradeType() {
+    return upgradeType;
+  }
+
+  /**
+   * @param upgradeType the upgrade type to set
+   */
+  public void setUpgradeType(UpgradeType upgradeType) {
+    this.upgradeType = upgradeType;
+  }
+
+  /**
+   * @return the upgrade package name, without the extension.
+   */
+  public String getUpgradePackage() {
+    return upgradePackage;
+  }
+
+  /**
+   * @param upgradePackage the upgrade pack to set
+   */
+  public void setUpgradePackage(String upgradePackage) {
+    this.upgradePackage = upgradePackage;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    UpgradeEntity that = (UpgradeEntity) o;
+
+    if (upgradeId != null ? !upgradeId.equals(that.upgradeId) : that.upgradeId 
!= null) {
+      return false;
+    }
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId 
!= null) {
+      return false;
+    }
+    if (requestId != null ? !requestId.equals(that.requestId) : that.requestId 
!= null) {
+      return false;
+    }
+    if (fromVersion != null ? !fromVersion.equals(that.fromVersion) : 
that.fromVersion != null) {
+      return false;
+    }
+    if (toVersion != null ? !toVersion.equals(that.toVersion) : that.toVersion 
!= null) {
+      return false;
+    }
+    if (direction != null ? !direction.equals(that.direction) : that.direction 
!= null) {
+      return false;
+    }
+    if (upgradeType != null ? !upgradeType.equals(that.upgradeType) : 
that.upgradeType != null) {
+      return false;
+    }
+    if (upgradePackage != null ? !upgradePackage.equals(that.upgradePackage) : 
that.upgradePackage != null) {
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = upgradeId != null ? upgradeId.hashCode() : 0;
+    result = 31 * result + (clusterId != null ? clusterId.hashCode() : 0);
+    result = 31 * result + (requestId != null ? requestId.hashCode() : 0);
+    result = 31 * result + (fromVersion != null ? fromVersion.hashCode() : 0);
+    result = 31 * result + (toVersion != null ? toVersion.hashCode() : 0);
+    result = 31 * result + (direction != null ? direction.hashCode() : 0);
+    result = 31 * result + (upgradeType != null ? upgradeType.hashCode() : 0);
+    result = 31 * result + (upgradePackage != null ? upgradePackage.hashCode() 
: 0);
+    return result;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java
----------------------------------------------------------------------
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 c717582..ef21a2a 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
@@ -46,7 +46,10 @@ import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
-import 
org.apache.ambari.server.state.stack.upgrade.ConfigureTask.ConfigurationKeyValue;
+import 
org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue;
+import 
org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer;
+import 
org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace;
+import 
org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Masked;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.gson.Gson;
@@ -176,27 +179,27 @@ public class ConfigureAction extends AbstractServerAction 
{
     String configType = 
commandParameters.get(ConfigureTask.PARAMETER_CONFIG_TYPE);
 
     // extract transfers
-    List<ConfigureTask.ConfigurationKeyValue> keyValuePairs = 
Collections.emptyList();
+    List<ConfigurationKeyValue> keyValuePairs = Collections.emptyList();
     String keyValuePairJson = 
commandParameters.get(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS);
     if (null != keyValuePairJson) {
       keyValuePairs = m_gson.fromJson(
-          keyValuePairJson, new 
TypeToken<List<ConfigureTask.ConfigurationKeyValue>>(){}.getType());
+          keyValuePairJson, new 
TypeToken<List<ConfigurationKeyValue>>(){}.getType());
     }
 
     // extract transfers
-    List<ConfigureTask.Transfer> transfers = Collections.emptyList();
+    List<Transfer> transfers = Collections.emptyList();
     String transferJson = 
commandParameters.get(ConfigureTask.PARAMETER_TRANSFERS);
     if (null != transferJson) {
       transfers = m_gson.fromJson(
-        transferJson, new 
TypeToken<List<ConfigureTask.Transfer>>(){}.getType());
+        transferJson, new TypeToken<List<Transfer>>(){}.getType());
     }
 
     // extract replacements
-    List<ConfigureTask.Replace> replacements = Collections.emptyList();
+    List<Replace> replacements = Collections.emptyList();
     String replaceJson = 
commandParameters.get(ConfigureTask.PARAMETER_REPLACEMENTS);
     if (null != replaceJson) {
       replacements = m_gson.fromJson(
-          replaceJson, new 
TypeToken<List<ConfigureTask.Replace>>(){}.getType());
+          replaceJson, new TypeToken<List<Replace>>(){}.getType());
     }
 
     // if there is nothing to do, then skip the task
@@ -240,7 +243,7 @@ public class ConfigureAction extends AbstractServerAction {
 
     // !!! do transfers first before setting defined values
     StringBuilder outputBuffer = new StringBuilder(250);
-    for (ConfigureTask.Transfer transfer : transfers) {
+    for (Transfer transfer : transfers) {
       switch (transfer.operation) {
         case COPY:
           String valueToCopy = null;
@@ -400,7 +403,7 @@ public class ConfigureAction extends AbstractServerAction {
     }
 
     // !!! string replacements happen only on the new values.
-    for (ConfigureTask.Replace replacement : replacements) {
+    for (Replace replacement : replacements) {
       if (newValues.containsKey(replacement.key)) {
         String toReplace = newValues.get(replacement.key);
 
@@ -534,7 +537,7 @@ public class ConfigureAction extends AbstractServerAction {
     return result;
   }
 
-  private static String mask(ConfigureTask.Masked mask, String value) {
+  private static String mask(Masked mask, String value) {
     if (mask.mask) {
       return StringUtils.repeat("*", value.length());
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/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/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java
index aa8e17b..9e2f997 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.stack;
 
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.ConfigurationXml;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.ServiceMetainfoXml;
@@ -63,12 +64,13 @@ class ModuleFileUnmarshaller {
     try {
       // three classes define the top-level element "metainfo", so we need 3 
contexts.
       JAXBContext ctx = JAXBContext.newInstance(StackMetainfoXml.class, 
RepositoryXml.class,
-          ConfigurationXml.class, UpgradePack.class);
+          ConfigurationXml.class, UpgradePack.class, ConfigUpgradePack.class);
 
       jaxbContexts.put(StackMetainfoXml.class, ctx);
       jaxbContexts.put(RepositoryXml.class, ctx);
       jaxbContexts.put(ConfigurationXml.class, ctx);
       jaxbContexts.put(UpgradePack.class, ctx);
+      jaxbContexts.put(ConfigUpgradePack.class, ctx);
       jaxbContexts.put(ServiceMetainfoXml.class, 
JAXBContext.newInstance(ServiceMetainfoXml.class));
     } catch (JAXBException e) {
       throw new RuntimeException (e);

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java
index 8f81b5a..c739211 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java
@@ -37,6 +37,8 @@ public abstract class StackDefinitionDirectory {
     }
   };
 
+  protected static final String CONFIG_UPGRADE_XML_FILENAME_PREFIX = 
"config-upgrade.xml";
+
   /**
    * underlying directory
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
index b849e88..90b8f10 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
@@ -23,6 +23,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.StackMetainfoXml;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.commons.io.FilenameUtils;
 import org.codehaus.jackson.map.ObjectMapper;
@@ -95,10 +96,14 @@ public class StackDirectory extends 
StackDefinitionDirectory {
   /**
    * map of upgrade pack name to upgrade pack
    */
-  //todo: should be a collection but upgrade pack doesn't have a name attribute
   private Map<String, UpgradePack> upgradePacks;
 
   /**
+   * Config delta from prev stack
+   */
+  private ConfigUpgradePack configUpgradePack;
+
+  /**
    * metainfo file representation
    */
   private StackMetainfoXml metaInfoXml;
@@ -255,6 +260,13 @@ public class StackDirectory extends 
StackDefinitionDirectory {
   }
 
   /**
+   * @return Config delta from prev stack or null if no config upgrade patches 
available
+   */
+  public ConfigUpgradePack getConfigUpgradePack() {
+    return configUpgradePack;
+  }
+
+  /**
    * Obtain the object representation of the stack role_command_order.json file
    *
    * @return object representation of the stack role_command_order.json file
@@ -409,18 +421,35 @@ public class StackDirectory extends 
StackDefinitionDirectory {
    * @throws AmbariException if unable to parse stack upgrade file
    */
   private void parseUpgradePacks(Collection<String> subDirs) throws 
AmbariException {
-    Map<String, UpgradePack> upgradeMap = new HashMap<String, UpgradePack>();
+    Map<String, UpgradePack> upgradeMap = new HashMap<>();
+    ConfigUpgradePack configUpgradePack = null;
     if (subDirs.contains(UPGRADE_PACK_FOLDER_NAME)) {
       File f = new File(getAbsolutePath() + File.separator + 
UPGRADE_PACK_FOLDER_NAME);
       if (f.isDirectory()) {
         upgradesDir = f.getAbsolutePath();
         for (File upgradeFile : f.listFiles(XML_FILENAME_FILTER)) {
-          try {
-            
upgradeMap.put(FilenameUtils.removeExtension(upgradeFile.getName()),
-                unmarshaller.unmarshal(UpgradePack.class, upgradeFile));
-          } catch (JAXBException e) {
-            throw new AmbariException("Unable to parse stack upgrade file at 
location: " +
-                upgradeFile.getAbsolutePath(), e);
+          if 
(upgradeFile.getName().toLowerCase().startsWith(CONFIG_UPGRADE_XML_FILENAME_PREFIX))
 {
+            try { // Parse config upgrade pack
+              if (configUpgradePack == null) {
+                configUpgradePack = 
unmarshaller.unmarshal(ConfigUpgradePack.class, upgradeFile);
+              } else { // If user messed things up with lower/upper case 
filenames
+                throw new AmbariException(String.format("There are multiple 
files with name like %s" +
+                        upgradeFile.getAbsolutePath()));
+              }
+            } catch (JAXBException e) {
+              throw new AmbariException("Unable to parse stack upgrade file at 
location: " +
+                      upgradeFile.getAbsolutePath(), e);
+            }
+          } else {
+            try {
+              String upgradePackName = 
FilenameUtils.removeExtension(upgradeFile.getName());
+              UpgradePack pack = unmarshaller.unmarshal(UpgradePack.class, 
upgradeFile);
+              pack.setName(upgradePackName);
+              upgradeMap.put(upgradePackName, pack);
+            } catch (JAXBException e) {
+              throw new AmbariException("Unable to parse stack upgrade file at 
location: " +
+                      upgradeFile.getAbsolutePath(), e);
+            }
           }
         }
       }
@@ -433,6 +462,13 @@ public class StackDirectory extends 
StackDefinitionDirectory {
     if (! upgradeMap.isEmpty()) {
       upgradePacks = upgradeMap;
     }
+
+    if (configUpgradePack != null) {
+      this.configUpgradePack = configUpgradePack;
+    } else {
+      LOG.info("Stack '{}' doesn't contain config upgrade pack file", 
getPath());
+    }
+
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
index 4fe7ed7..def33f0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
@@ -22,7 +22,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -422,6 +421,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
       
stackInfo.setWidgetsDescriptorFileLocation(stackDirectory.getWidgetsDescriptorFilePath());
       stackInfo.setUpgradesFolder(stackDirectory.getUpgradesDir());
       stackInfo.setUpgradePacks(stackDirectory.getUpgradePacks());
+      stackInfo.setConfigUpgradePack(stackDirectory.getConfigUpgradePack());
       stackInfo.setRoleCommandOrder(stackDirectory.getRoleCommandOrder());
       populateConfigurationModules();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index 8e9d092..e3ac3e0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -31,6 +31,7 @@ import java.util.Set;
 import org.apache.ambari.server.controller.StackVersionResponse;
 import org.apache.ambari.server.stack.Validable;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack;
 
 public class StackInfo implements Comparable<StackInfo>, Validable{
@@ -67,6 +68,7 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable{
   private List<PropertyInfo> properties;
   private Map<String, Map<String, Map<String, String>>> configTypes;
   private Map<String, UpgradePack> upgradePacks;
+  private ConfigUpgradePack configUpgradePack;
   private StackRoleCommandOrder roleCommandOrder;
   private boolean valid = true;
 
@@ -373,23 +375,40 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable{
   }
 
   /**
+   * Obtain all stack upgrade packs.
+   *
+   * @return map of upgrade pack name to upgrade pack or {@code null} if no 
packs
+   */
+  public Map<String, UpgradePack> getUpgradePacks() {
+    return upgradePacks;
+  }
+
+  /**
    * Set upgrade packs.
    *
-   * @param upgradePacks  map of upgrade packs
+   * @param upgradePacks map of upgrade packs
    */
   public void setUpgradePacks(Map<String, UpgradePack> upgradePacks) {
     this.upgradePacks = upgradePacks;
   }
 
   /**
-   * Obtain all stack upgrade packs.
-   *
-   * @return map of upgrade pack name to upgrade pack or {@code null} of no 
packs
+   * Get config upgrade pack for stack
+   * @return config upgrade pack for stack or null if it is
+   * not defined
    */
-  public Map<String, UpgradePack> getUpgradePacks() {
-    return upgradePacks;
+  public ConfigUpgradePack getConfigUpgradePack() {
+    return configUpgradePack;
   }
 
+  /**
+   * Set config upgrade pack for stack
+   * @param configUpgradePack config upgrade pack for stack or null if it is
+   * not defined
+   */
+  public void setConfigUpgradePack(ConfigUpgradePack configUpgradePack) {
+    this.configUpgradePack = configUpgradePack;
+  }
 
   @Override
   public int compareTo(StackInfo o) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/c58162fe/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 b10db9e..7f307cf 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
@@ -25,6 +25,7 @@ import java.util.Map;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.stack.upgrade.Direction;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 /**
  * Used to hold various helper objects required to process an upgrade pack.
@@ -41,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}.
@@ -54,6 +63,7 @@ public class UpgradeContext {
   private Map<String, String> m_serviceNames = new HashMap<String, String>();
   private Map<String, String> m_componentNames = new HashMap<String, String>();
   private String m_downgradeFromVersion = null;
+  private UpgradeType m_type = null;
 
   /**
    * {@code true} if slave/client component failures should be automatically
@@ -88,15 +98,31 @@ public class UpgradeContext {
    *          the target version to upgrade to
    * @param direction
    *          the direction for the upgrade
+   * @param type
+   *          the type of upgrade, either rolling or non_rolling
    */
   public UpgradeContext(MasterHostResolver resolver, StackId sourceStackId,
       StackId targetStackId, String version,
-      Direction direction) {
+      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;
+    m_type = type;
   }
 
   /**
@@ -121,6 +147,13 @@ public class UpgradeContext {
   }
 
   /**
+   * @return the type of upgrade.
+   */
+  public UpgradeType getType() {
+    return m_type;
+  }
+
+  /**
    * @return the resolver
    */
   public MasterHostResolver getResolver() {
@@ -164,6 +197,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/c58162fe/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 75c04da..f0b383c 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
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.state;
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -42,6 +43,8 @@ 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.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.stack.UpgradePack;
@@ -49,11 +52,18 @@ import 
org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.state.stack.upgrade.Grouping;
 import org.apache.ambari.server.state.stack.upgrade.ManualTask;
+import org.apache.ambari.server.state.stack.upgrade.RestartGrouping;
+import org.apache.ambari.server.state.stack.upgrade.RestartTask;
 import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
 import org.apache.ambari.server.state.stack.upgrade.StageWrapperBuilder;
+import org.apache.ambari.server.state.stack.upgrade.StartGrouping;
+import org.apache.ambari.server.state.stack.upgrade.StartTask;
+import org.apache.ambari.server.state.stack.upgrade.StopGrouping;
+import org.apache.ambari.server.state.stack.upgrade.StopTask;
 import org.apache.ambari.server.state.stack.upgrade.Task;
 import org.apache.ambari.server.state.stack.upgrade.Task.Type;
 import org.apache.ambari.server.state.stack.upgrade.TaskWrapper;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -171,6 +181,68 @@ public class UpgradeHelper {
   @Inject
   private Provider<AmbariMetaInfo> m_ambariMetaInfo;
 
+  @Inject
+  private Provider<Clusters> clusters;
+
+  @Inject
+  private Provider<RepositoryVersionDAO> s_repoVersionDAO;
+
+
+  /**
+   * Get right Upgrade Pack, depends on stack, direction and upgrade type 
information
+   * @param clusterName The name of the cluster
+   * @param upgradeFromVersion Current stack version
+   * @param upgradeToVersion Target stack version
+   * @param direction {@code Direction} of the upgrade
+   * @param upgradeType The {@code UpgradeType}
+   * @return {@code UpgradeType} object
+   * @throws AmbariException
+   */
+  public UpgradePack suggestUpgradePack(String clusterName, String 
upgradeFromVersion, String upgradeToVersion,
+    Direction direction, UpgradeType upgradeType) throws AmbariException {
+
+    // !!! find upgrade packs based on current stack. This is where to upgrade 
from
+    Cluster cluster = clusters.get().getCluster(clusterName);
+    StackId stack =  cluster.getCurrentStackVersion();
+
+    String repoVersion = upgradeToVersion;
+
+    // ToDo: AMBARI-12706. Here we need to check, how this would work with SWU 
Downgrade
+    if (direction.isDowngrade() && null != upgradeFromVersion) {
+      repoVersion = upgradeFromVersion;
+    }
+
+    RepositoryVersionEntity versionEntity = 
s_repoVersionDAO.get().findByStackNameAndVersion(stack.getStackName(), 
repoVersion);
+
+    if (versionEntity == null) {
+      throw new AmbariException(String.format("Repository version %s was not 
found", repoVersion));
+    }
+
+    Map<String, UpgradePack> packs = 
m_ambariMetaInfo.get().getUpgradePacks(stack.getStackName(), 
stack.getStackVersion());
+    UpgradePack pack = null;
+
+    String repoStackId = versionEntity.getStackId().getStackId();
+    for (UpgradePack upgradePack : packs.values()) {
+      if (upgradePack.getTargetStack() != null && 
upgradePack.getTargetStack().equals(repoStackId) &&
+           upgradeType == upgradePack.getType()) {
+        if (pack == null) {
+          pack = upgradePack;
+        } else {
+          throw new AmbariException(
+            String.format("Found multiple upgrade packs for type %s and target 
version %s",
+              upgradeType.toString(), repoVersion));
+        }
+      }
+    }
+
+    if (pack == null) {
+      throw new AmbariException(String.format("No upgrade pack found for type 
%s and target version %s",
+        upgradeType.toString(),repoVersion));
+    }
+
+   return pack;
+  }
+
 
   /**
    * Generates a list of UpgradeGroupHolder items that are used to execute 
either
@@ -189,14 +261,16 @@ public class UpgradeHelper {
     Cluster cluster = context.getCluster();
     MasterHostResolver mhr = context.getResolver();
 
+    // Note, only a Rolling Upgrade uses processing tasks.
     Map<String, Map<String, ProcessingComponent>> allTasks = 
upgradePack.getTasks();
-    List<UpgradeGroupHolder> groups = new ArrayList<UpgradeGroupHolder>();
+    List<UpgradeGroupHolder> groups = new ArrayList<>();
 
     for (Grouping group : upgradePack.getGroups(context.getDirection())) {
 
       UpgradeGroupHolder groupHolder = new UpgradeGroupHolder();
       groupHolder.name = group.name;
       groupHolder.title = group.title;
+      groupHolder.groupClass = group.getClass();
       groupHolder.skippable = group.skippable;
       groupHolder.allowRetry = group.allowRetry;
 
@@ -205,29 +279,52 @@ public class UpgradeHelper {
         groupHolder.skippable = true;
       }
 
+      // NonRolling defaults to not performing service checks on a group.
+      // Of course, a Service Check Group does indeed run them.
+      if (upgradePack.getType() == UpgradeType.NON_ROLLING) {
+        group.performServiceCheck = false;
+      }
+
       StageWrapperBuilder builder = group.getBuilder();
 
       List<UpgradePack.OrderService> services = group.services;
 
-      if (context.getDirection().isDowngrade() && !services.isEmpty()) {
-        List<UpgradePack.OrderService> reverse = new 
ArrayList<UpgradePack.OrderService>(services);
-        Collections.reverse(reverse);
-        services = reverse;
+      // Rolling Downgrade must reverse the order of services.
+      if (upgradePack.getType() == UpgradeType.ROLLING) {
+        if (context.getDirection().isDowngrade() && !services.isEmpty()) {
+          List<UpgradePack.OrderService> reverse = new ArrayList<>(services);
+          Collections.reverse(reverse);
+          services = reverse;
+        }
       }
 
       // !!! cluster and service checks are empty here
       for (UpgradePack.OrderService service : services) {
 
-        if (!allTasks.containsKey(service.serviceName)) {
+        if (upgradePack.getType() == UpgradeType.ROLLING && 
!allTasks.containsKey(service.serviceName)) {
           continue;
         }
+        
+        // Attempt to get the function of the group, during a NonRolling 
Upgrade
+        Task.Type functionName = null;
+
+        if (RestartGrouping.class.isInstance(group)) {
+          functionName = ((RestartGrouping) group).getFunction();
+        }
+        if (StartGrouping.class.isInstance(group)) {
+          functionName = ((StartGrouping) group).getFunction();
+        }
+        if (StopGrouping.class.isInstance(group)) {
+          functionName = ((StopGrouping) group).getFunction();
+        }
 
         for (String component : service.components) {
-          if (!allTasks.get(service.serviceName).containsKey(component)) {
+          if (upgradePack.getType() == UpgradeType.ROLLING && 
!allTasks.get(service.serviceName).containsKey(component)) {
             continue;
           }
-
+          
           HostsType hostsType = mhr.getMasterAndHosts(service.serviceName, 
component);
+          // TODO AMBARI-12698, how does this impact SECONDARY NAMENODE if 
there's no NameNode HA?
           if (null == hostsType) {
             continue;
           }
@@ -237,7 +334,31 @@ public class UpgradeHelper {
           }
 
           Service svc = cluster.getService(service.serviceName);
-          ProcessingComponent pc = 
allTasks.get(service.serviceName).get(component);
+
+          ProcessingComponent pc = null;
+          if (upgradePack.getType() == UpgradeType.ROLLING) {
+            pc = allTasks.get(service.serviceName).get(component);
+          } else if (upgradePack.getType() == UpgradeType.NON_ROLLING) {
+            // Construct a processing task on-the-fly
+            if (null != functionName) {
+              pc = new ProcessingComponent();
+              pc.name = component;
+              pc.tasks = new ArrayList<>();
+
+              if (functionName == Type.START) {
+                pc.tasks.add(new StartTask());
+              } else if (functionName == Type.STOP) {
+                pc.tasks.add(new StopTask());
+              } else if (functionName == Type.RESTART) {
+                pc.tasks.add(new RestartTask());
+              }
+            }
+          }
+
+          if (pc == null) {
+            LOG.error(MessageFormat.format("Couldn't create a processing 
component for service {0} and component {1}.", service.serviceName, component));
+            continue;
+          }
 
           setDisplayNames(context, service.serviceName, component);
 
@@ -246,7 +367,7 @@ public class UpgradeHelper {
             // !!! revisit if needed
             if (!hostsType.hosts.isEmpty() && hostsType.master != null && 
hostsType.secondary != null) {
               // The order is important, first do the standby, then the active 
namenode.
-              LinkedHashSet<String> order = new LinkedHashSet<String>();
+              LinkedHashSet<String> order = new LinkedHashSet<>();
 
               order.add(hostsType.secondary);
               order.add(hostsType.master);
@@ -342,7 +463,7 @@ public class UpgradeHelper {
 
     String result = source;
 
-    List<String> tokens = new ArrayList<String>(5);
+    List<String> tokens = new ArrayList<>(5);
     Matcher matcher = PLACEHOLDER_REGEX.matcher(source);
     while (matcher.find()) {
       tokens.add(matcher.group(1));
@@ -424,6 +545,9 @@ public class UpgradeHelper {
      */
     public String title;
 
+
+    public Class<? extends Grouping> groupClass;
+
     /**
      * Indicate whether retry is allowed for the stages in this group.
      */
@@ -438,7 +562,7 @@ public class UpgradeHelper {
     /**
      * List of stages for the group
      */
-    public List<StageWrapper> items = new ArrayList<StageWrapper>();
+    public List<StageWrapper> items = new ArrayList<>();
 
     /**
      * {@inheritDoc}
@@ -521,8 +645,5 @@ public class UpgradeHelper {
     } catch (AmbariException e) {
       LOG.debug("Could not get service detail", e);
     }
-
-
   }
-
 }

Reply via email to