You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2015/01/26 16:55:30 UTC

ambari git commit: AMBARI-9313. Expose Upgrade/Downgrade State To Service Python Framework (ncole)

Repository: ambari
Updated Branches:
  refs/heads/trunk d8dc285a5 -> 6c649d0a7


AMBARI-9313. Expose Upgrade/Downgrade State To Service Python Framework (ncole)


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

Branch: refs/heads/trunk
Commit: 6c649d0a70d2fe7a6bee99d2f0e7d2c6b986d42f
Parents: d8dc285
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Jan 23 17:37:18 2015 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Mon Jan 26 10:55:22 2015 -0500

----------------------------------------------------------------------
 .../internal/UpgradeResourceProvider.java       | 123 +++++++++---------
 .../ambari/server/state/UpgradeContext.java     |  89 +++++++++++++
 .../ambari/server/state/UpgradeHelper.java      | 130 +++----------------
 .../state/stack/upgrade/ClusterGrouping.java    |  15 +--
 .../state/stack/upgrade/ColocatedGrouping.java  |   3 +-
 .../server/state/stack/upgrade/Direction.java   |  26 ++++
 .../server/state/stack/upgrade/Grouping.java    |   3 +-
 .../stack/upgrade/ServiceCheckGrouping.java     |  15 +--
 .../stack/upgrade/StageWrapperBuilder.java      |   5 +-
 .../stacks/HDP/2.2/upgrades/upgrade-2.2.xml     |   1 +
 .../internal/UpgradeResourceProviderTest.java   |  24 ++++
 .../ambari/server/state/UpgradeHelperTest.java  |  31 +++--
 12 files changed, 256 insertions(+), 209 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/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 746a04a..91b8c98 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
@@ -70,10 +70,12 @@ import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeHelper;
 import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.state.stack.upgrade.ManualTask;
 import org.apache.ambari.server.state.stack.upgrade.ServerSideActionTask;
 import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
@@ -106,6 +108,11 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       Arrays.asList(UPGRADE_REQUEST_ID, UPGRADE_CLUSTER_NAME));
   private static final Set<String> PROPERTY_IDS = new HashSet<String>();
 
+  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";
+  private static final String COMMAND_PARAM_RESTART_TYPE = "restart_type";
+  private static final String COMMAND_PARAM_TASKS = "tasks";
 
   private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>();
 
@@ -189,9 +196,19 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     UpgradeEntity entity = createResources(new Command<UpgradeEntity>() {
         @Override
         public UpgradeEntity invoke() throws AmbariException {
-          UpgradePack up = validateRequest(requestMap, requestInfoProps);
+          String forceDowngrade = requestInfoProps.get(UpgradeResourceDefinition.DOWNGRADE_DIRECTIVE);
 
-          return createUpgrade(up, requestMap, requestInfoProps);
+          // check the property if the directive is not specified...
+          if (forceDowngrade == null) {
+            forceDowngrade = (String) requestMap.get(UPGRADE_FORCE_DOWNGRADE);
+          }
+
+          Direction direction = Boolean.parseBoolean(forceDowngrade) ?
+              Direction.DOWNGRADE : Direction.UPGRADE;
+
+          UpgradePack up = validateRequest(direction, requestMap);
+
+          return createUpgrade(direction, up, requestMap);
         }
       });
 
@@ -265,24 +282,14 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       Predicate predicate)
       throws SystemException, UnsupportedPropertyException,
       NoSuchResourceException, NoSuchParentResourceException {
-
-    modifyResources(new Command<Void>() {
-      @Override
-      public Void invoke() throws AmbariException {
-        return null;
-      }
-    });
-
-    notifyUpdate(Resource.Type.Upgrade, request, predicate);
-
-    return getRequestStatus(null);
+    throw new SystemException("Cannot update Upgrades");
   }
 
   @Override
   public RequestStatus deleteResources(Predicate predicate)
       throws SystemException, UnsupportedPropertyException,
       NoSuchResourceException, NoSuchParentResourceException {
-    throw new SystemException("Cannot delete upgrades");
+    throw new SystemException("Cannot delete Upgrades");
   }
 
   @Override
@@ -309,18 +316,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
    * @return the validated upgrade pack
    * @throws AmbariException
    */
-  private UpgradePack validateRequest(Map<String, Object> requestMap, Map<String, String> requestInfoProps)
+  private UpgradePack validateRequest(Direction direction, Map<String, Object> requestMap)
       throws AmbariException {
     String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);
     String version = (String) requestMap.get(UPGRADE_VERSION);
     String versionForUpgradePack = (String) requestMap.get(UPGRADE_FROM_VERSION);
 
-    String forceDowngrade = requestInfoProps.get(UpgradeResourceDefinition.DOWNGRADE_DIRECTIVE);
-
-    // check the property if the directive is not specified...
-    if (forceDowngrade == null) {
-      forceDowngrade = (String) requestMap.get(UPGRADE_FORCE_DOWNGRADE);
-    }
 
     if (null == clusterName) {
       throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
@@ -335,7 +336,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
     String repoVersion = version;
 
-    if (Boolean.valueOf(forceDowngrade) && null != versionForUpgradePack) {
+    if (direction == Direction.DOWNGRADE && null != versionForUpgradePack) {
       repoVersion = versionForUpgradePack;
     }
 
@@ -354,8 +355,10 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
     if (null == up) {
       throw new AmbariException(String.format(
-          "Upgrade pack %s for version %s not found", versionEntity.getUpgradePackage(),
-            repoVersion));
+          "Unable to perform %s.  Could not locate upgrade pack %s for version %s",
+          direction == Direction.DOWNGRADE ? "downgrade" : "upgrade",
+          versionEntity.getUpgradePackage(),
+          repoVersion));
     }
 
     // !!! validate all hosts have the version installed
@@ -393,9 +396,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     }
   }
 
-  private UpgradeEntity createUpgrade(UpgradePack pack,
-                                      Map<String, Object> requestMap,
-                                      Map<String, String> requestInfoProps) throws AmbariException {
+  private UpgradeEntity createUpgrade(Direction direction, UpgradePack pack,
+                                      Map<String, Object> requestMap) throws AmbariException {
 
     String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);
 
@@ -406,25 +408,14 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     Cluster cluster = getManagementController().getClusters().getCluster(clusterName);
     ConfigHelper configHelper = getManagementController().getConfigHelper();
 
-    String forceDowngrade = requestInfoProps.get(UpgradeResourceDefinition.DOWNGRADE_DIRECTIVE);
-
-    // check the property if the directive is not specified...
-    if (forceDowngrade == null) {
-      forceDowngrade = (String) requestMap.get(UPGRADE_FORCE_DOWNGRADE);
-    }
-
-    List<UpgradeGroupHolder> groups = null;
-
     // the version being upgraded or downgraded to (ie hdp-2.2.1.0-1234)
     final String version = (String) requestMap.get(UPGRADE_VERSION);
 
-    if (Boolean.valueOf(forceDowngrade)) {
-      MasterHostResolver mhr = new MasterHostResolver(cluster, version);
-      groups = s_upgradeHelper.createDowngrade(mhr, pack, version);
-    } else {
-      MasterHostResolver mhr = new MasterHostResolver(cluster);
-      groups = s_upgradeHelper.createUpgrade(mhr, pack, version);
-    }
+    UpgradeContext ctx = new UpgradeContext(direction == Direction.UPGRADE ?
+        new MasterHostResolver(cluster) : new MasterHostResolver(cluster, version),
+        version, direction);
+
+    List<UpgradeGroupHolder> groups = s_upgradeHelper.createSequence(pack, ctx);
 
     if (groups.isEmpty()) {
       throw new AmbariException("There are no upgrade groupings available");
@@ -458,7 +449,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
               injectVariables(configHelper, cluster, itemEntity);
 
-              makeServerSideStage(cluster, req, version, itemEntity, (ServerSideActionTask) task, skippable, allowRetry);
+              makeServerSideStage(ctx, req, itemEntity, (ServerSideActionTask) task, skippable, allowRetry);
             }
           }
         } else {
@@ -471,7 +462,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           injectVariables(configHelper, cluster, itemEntity);
 
           // upgrade items match a stage
-          createStage(cluster, req, version, itemEntity, wrapper, skippable, allowRetry);
+          createStage(ctx, req, itemEntity, wrapper, skippable, allowRetry);
         }
       }
 
@@ -509,26 +500,26 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     return requestStages;
   }
 
-  private void createStage(Cluster cluster, RequestStageContainer request, final String version,
+  private void createStage(UpgradeContext context, RequestStageContainer request,
       UpgradeItemEntity entity, StageWrapper wrapper, boolean skippable, boolean allowRetry)
       throws AmbariException {
 
     switch (wrapper.getType()) {
       case RESTART:
-        makeRestartStage(cluster, request, version, entity, wrapper, skippable, allowRetry);
+        makeRestartStage(context, request, entity, wrapper, skippable, allowRetry);
         break;
       case RU_TASKS:
-        makeActionStage(cluster, request, version, entity, wrapper, skippable, allowRetry);
+        makeActionStage(context, request, entity, wrapper, skippable, allowRetry);
         break;
       case SERVICE_CHECK:
-          makeServiceCheckStage(cluster, request, version, entity, wrapper, skippable, allowRetry);
+        makeServiceCheckStage(context, request, entity, wrapper, skippable, allowRetry);
         break;
       default:
         break;
     }
   }
 
-  private void makeActionStage(Cluster cluster, RequestStageContainer request, final String version,
+  private void makeActionStage(UpgradeContext context, RequestStageContainer request,
                                UpgradeItemEntity entity, StageWrapper wrapper,
                                boolean skippable, boolean allowRetry) throws AmbariException {
 
@@ -537,13 +528,16 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           String.format("Cannot create action for '%s' with no hosts", wrapper.getText()));
     }
 
+    Cluster cluster = context.getCluster();
+
     // add each host to this stage
     RequestResourceFilter filter = new RequestResourceFilter("", "",
         new ArrayList<String>(wrapper.getHosts()));
 
     Map<String, String> params = new HashMap<String, String>();
-    params.put("tasks", entity.getTasks());
-    params.put("version", version);
+    params.put(COMMAND_PARAM_TASKS, entity.getTasks());
+    params.put(COMMAND_PARAM_VERSION, context.getVersion());
+    params.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());
 
     // Because custom task may end up calling a script/function inside a service, it is necessary to set the
     // service_package_folder and hooks_folder params.
@@ -602,10 +596,12 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     request.addStages(Collections.singletonList(stage));
   }
 
-  private void makeRestartStage(Cluster cluster, RequestStageContainer request, final String version,
+  private void makeRestartStage(UpgradeContext context, RequestStageContainer request,
                                 UpgradeItemEntity entity, StageWrapper wrapper,
                                 boolean skippable, boolean allowRetry) throws AmbariException {
 
+    Cluster cluster = context.getCluster();
+
     List<RequestResourceFilter> filters = new ArrayList<RequestResourceFilter>();
 
     for (TaskWrapper tw : wrapper.getTasks()) {
@@ -615,8 +611,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     }
 
     Map<String, String> restartCommandParams = new HashMap<String, String>();
-    restartCommandParams.put("restart_type", "rolling_upgrade");
-    restartCommandParams.put("version", version);
+    restartCommandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade");
+    restartCommandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
+    restartCommandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());
 
     ActionExecutionContext actionContext = new ActionExecutionContext(
         cluster.getClusterName(), "RESTART",
@@ -655,7 +652,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     request.addStages(Collections.singletonList(stage));
   }
 
-  private void makeServiceCheckStage(Cluster cluster, RequestStageContainer request, String version,
+  private void makeServiceCheckStage(UpgradeContext context, RequestStageContainer request,
                                      UpgradeItemEntity entity, StageWrapper wrapper,
                                      boolean skippable, boolean allowRetry) throws AmbariException {
 
@@ -665,8 +662,11 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       filters.add(new RequestResourceFilter(tw.getService(), "", Collections.<String>emptyList()));
     }
 
+    Cluster cluster = context.getCluster();
+
     Map<String, String> commandParams = new HashMap<String, String>();
-    commandParams.put("version", version);
+    commandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
+    commandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());
 
     ActionExecutionContext actionContext = new ActionExecutionContext(
         cluster.getClusterName(), "SERVICE_CHECK",
@@ -702,13 +702,16 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     request.addStages(Collections.singletonList(stage));
   }
 
-  private void makeServerSideStage(Cluster cluster, RequestStageContainer request, String version,
+  private void makeServerSideStage(UpgradeContext context, RequestStageContainer request,
                                    UpgradeItemEntity entity, ServerSideActionTask task,
                                    boolean skippable, boolean allowRtery) throws AmbariException {
 
+    Cluster cluster = context.getCluster();
+
     Map<String, String> commandParams = new HashMap<String, String>();
-    commandParams.put("clusterName", cluster.getClusterName());
-    commandParams.put("version", version);
+    commandParams.put(COMMAND_PARAM_CLUSTER_NAME, cluster.getClusterName());
+    commandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
+    commandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());
 
     String itemDetail = entity.getText();
     String stageText = StringUtils.abbreviate(entity.getText(), 255);

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/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
new file mode 100644
index 0000000..c0514c5
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.stack.MasterHostResolver;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
+
+/**
+ * Used to hold various helper objects required to process an upgrade pack.
+ */
+public class UpgradeContext {
+
+  private String m_version;
+  private Direction m_direction;
+  private MasterHostResolver m_resolver;
+  private AmbariMetaInfo m_metaInfo;
+
+  /**
+   * Constructor.
+   * @param resolver  the resolver that also references the required cluster
+   * @param version   the target version to upgrade to
+   * @param direction the direction for the upgrade
+   */
+  public UpgradeContext(MasterHostResolver resolver, String version,
+      Direction direction) {
+    m_version = version;
+    m_direction = direction;
+    m_resolver = resolver;
+  }
+
+  /**
+   * @return the cluster from the {@link MasterHostResolver}
+   */
+  public Cluster getCluster() {
+    return m_resolver.getCluster();
+  }
+
+  /**
+   * @return the target version for the upgrade
+   */
+  public String getVersion() {
+    return m_version;
+  }
+
+  /**
+   * @return the direction of the upgrade
+   */
+  public Direction getDirection() {
+    return m_direction;
+  }
+
+  /**
+   * @return the resolver
+   */
+  public MasterHostResolver getResolver() {
+    return m_resolver;
+  }
+
+  /**
+   * @return the metainfo for access to service definitions
+   */
+  public AmbariMetaInfo getAmbariMetaInfo() {
+    return m_metaInfo;
+  }
+
+  /**
+   * @param metaInfo the metainfo for access to service definitions
+   */
+  public void setAmbariMetaInfo(AmbariMetaInfo metaInfo) {
+    m_metaInfo = metaInfo;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/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 e3d8619..5a4879d 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
@@ -48,10 +48,9 @@ import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
-import org.apache.ambari.server.state.stack.upgrade.ClusterGrouping;
+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.ServiceCheckGrouping;
 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.Task;
@@ -116,101 +115,30 @@ public class UpgradeHelper {
   @Inject
   private Provider<AmbariMetaInfo> m_ambariMetaInfo;
 
-  /**
-   * Generates a list of UpgradeGroupHolder items that are used to execute a
-   * downgrade
-   *
-   * @param mhr
-   *          Master Host Resolver needed to get master and secondary hosts of
-   *          several components like NAMENODE
-   * @param upgradePack
-   *          the upgrade pack
-   * @param version
-   *          the version of the stack that the downgrade to, such as
-   *          {@code 2.2.0.0-2041}.
-   * @return the list of holders
-   */
-  public List<UpgradeGroupHolder> createDowngrade(MasterHostResolver mhr,
-      UpgradePack upgradePack, String version) throws AmbariException {
-    return createSequence(mhr, upgradePack, version, false);
-  }
 
   /**
-   * Generates a list of UpgradeGroupHolder items that are used to execute an
-   * upgrade
+   * Generates a list of UpgradeGroupHolder items that are used to execute either
+   * an upgrade or a downgrade.
    *
-   * @param mhr
-   *          Master Host Resolver needed to get master and secondary hosts of
-   *          several components like NAMENODE
    * @param upgradePack
    *          the upgrade pack
-   * @param version
-   *          the version of the stack that the upgrade is to, such as
-   *          {@code 2.2.0.0-2041}.
+   * @param context
+   *          the context that wraps key fields required to perform an upgrade
    * @return the list of holders
    */
-  public List<UpgradeGroupHolder> createUpgrade(MasterHostResolver mhr,
-      UpgradePack upgradePack, String version) throws AmbariException {
-    return createSequence(mhr, upgradePack, version, true);
-  }
+  public List<UpgradeGroupHolder> createSequence(UpgradePack upgradePack,
+      UpgradeContext context) throws AmbariException {
 
+    context.setAmbariMetaInfo(m_ambariMetaInfo.get());
+    Cluster cluster = context.getCluster();
+    boolean forUpgrade = context.getDirection() == Direction.UPGRADE;
+    MasterHostResolver mhr = context.getResolver();
+    String version = context.getVersion();
 
-  /**
-   * Generates a list of UpgradeGroupHolder items that are used to execute an
-   * upgrade
-   *
-   * @param mhr
-   *          Master Host Resolver needed to get master and secondary hosts of
-   *          several components like NAMENODE
-   * @param upgradePack
-   *          the upgrade pack
-   * @param version
-   *          the version of the stack that the upgrade or downgrade is to, such
-   *          as {@code 2.2.0.0-2041}.
-   * @param forUpgrade
-   *          {@code true} if the sequence is for an upgrade, {@code false} if
-   *          for a downgrade
-   * @return the list of holders
-   *
-   */
-  private List<UpgradeGroupHolder> createSequence(MasterHostResolver mhr,
-      UpgradePack upgradePack, String version, boolean forUpgrade)
-      throws AmbariException {
-
-    Cluster cluster = mhr.getCluster();
     Map<String, Map<String, ProcessingComponent>> allTasks = upgradePack.getTasks();
     List<UpgradeGroupHolder> groups = new ArrayList<UpgradeGroupHolder>();
 
-
     for (Grouping group : upgradePack.getGroups(forUpgrade)) {
-      if (ClusterGrouping.class.isInstance(group)) {
-        UpgradeGroupHolder groupHolder = getClusterGroupHolder(
-            cluster, (ClusterGrouping) group, forUpgrade ? null : version);
-
-        if (null != groupHolder) {
-          groups.add(groupHolder);
-        }
-
-        continue;
-      } else if (ServiceCheckGrouping.class.isInstance(group)) {
-        ServiceCheckGrouping scg = (ServiceCheckGrouping) group;
-
-        scg.getBuilder().setHelpers(cluster, m_ambariMetaInfo.get());
-
-        List<StageWrapper> wrappers = scg.getBuilder().build();
-
-        if (!wrappers.isEmpty()) {
-          UpgradeGroupHolder groupHolder = new UpgradeGroupHolder();
-          groupHolder.name = group.name;
-          groupHolder.title = group.title;
-          groupHolder.skippable = group.skippable;
-          groupHolder.allowRetry = group.allowRetry;
-          groupHolder.items = wrappers;
-          groups.add(groupHolder);
-        }
-
-        continue;
-      }
 
       UpgradeGroupHolder groupHolder = new UpgradeGroupHolder();
       groupHolder.name = group.name;
@@ -222,12 +150,13 @@ public class UpgradeHelper {
 
       List<UpgradePack.OrderService> services = group.services;
 
-      if (!forUpgrade) {
+      if (context.getDirection() == Direction.DOWNGRADE && !services.isEmpty()) {
         List<UpgradePack.OrderService> reverse = new ArrayList<UpgradePack.OrderService>(services);
         Collections.reverse(reverse);
         services = reverse;
       }
 
+      // !!! cluster and service checks are empty here
       for (UpgradePack.OrderService service : services) {
 
         if (!allTasks.containsKey(service.serviceName)) {
@@ -274,7 +203,7 @@ public class UpgradeHelper {
         }
       }
 
-      List<StageWrapper> proxies = builder.build();
+      List<StageWrapper> proxies = builder.build(context);
 
       // post process all of the tasks
       postProcessTasks(proxies, mhr, version);
@@ -491,33 +420,4 @@ public class UpgradeHelper {
     return resources.iterator().next();
   }
 
-  /**
-   * Special handling for ClusterGrouping that is used for tasks that are
-   * to run on a specific targeted HostComponent.
-   *
-   * @param cluster   the cluster
-   * @param grouping  the grouping
-   * @param version   the version used to create a {@link MasterHostResolver}
-   * @return the holder, or {@code null} if there are no clustergrouping tasks.
-   */
-  private UpgradeGroupHolder getClusterGroupHolder(Cluster cluster,
-      ClusterGrouping grouping, String version) {
-
-    grouping.getBuilder().setHelpers(new MasterHostResolver(cluster, version));
-    List<StageWrapper> wrappers = grouping.getBuilder().build();
-
-    if (wrappers.size() > 0) {
-      UpgradeGroupHolder holder = new UpgradeGroupHolder();
-      holder.name = grouping.name;
-      holder.title = grouping.title;
-      holder.items = wrappers;
-
-      return holder;
-    }
-
-
-    return null;
-
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
index f8af353..8e2100c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
@@ -32,7 +32,7 @@ import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.ambari.server.stack.HostsType;
-import org.apache.ambari.server.stack.MasterHostResolver;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 
 /**
@@ -79,14 +79,6 @@ public class ClusterGrouping extends Grouping {
   }
 
   public class ClusterBuilder extends StageWrapperBuilder {
-    private MasterHostResolver m_resolver = null;
-
-    /**
-     * @param resolver  the resolver to use
-     */
-    public void setHelpers(MasterHostResolver resolver) {
-      m_resolver = resolver;
-    }
 
     @Override
     public void add(HostsType hostsType, String service,
@@ -95,7 +87,7 @@ public class ClusterGrouping extends Grouping {
     }
 
     @Override
-    public List<StageWrapper> build() {
+    public List<StageWrapper> build(UpgradeContext ctx) {
       if (null == ClusterGrouping.this.executionStages) {
         return Collections.emptyList();
       }
@@ -111,7 +103,8 @@ public class ClusterGrouping extends Grouping {
           if (null != execution.service && !execution.service.isEmpty() &&
               null != execution.component && !execution.component.isEmpty()) {
 
-            HostsType hosts = m_resolver.getMasterAndHosts(execution.service, execution.component);
+            HostsType hosts = ctx.getResolver().getMasterAndHosts(
+                execution.service, execution.component);
 
             if (null == hosts) {
               continue;

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
index c5126dd..61fab0b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ColocatedGrouping.java
@@ -30,6 +30,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.ambari.server.stack.HostsType;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -133,7 +134,7 @@ public class ColocatedGrouping extends Grouping {
 
 
     @Override
-    public List<StageWrapper> build() {
+    public List<StageWrapper> build(UpgradeContext ctx) {
       List<StageWrapper> results = new ArrayList<StageWrapper>();
 
       if (LOG.isDebugEnabled()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
new file mode 100644
index 0000000..373bf23
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Direction.java
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+/**
+ * Indicates if an sequence of Groups should be for an upgrade or a downgrade.
+ */
+public enum Direction {
+  UPGRADE,
+  DOWNGRADE
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/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 7eeb325..fe911c8 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
@@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 
 import org.apache.ambari.server.stack.HostsType;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 import org.apache.commons.lang.StringUtils;
@@ -130,7 +131,7 @@ public class Grouping {
     }
 
     @Override
-    public List<StageWrapper> build() {
+    public List<StageWrapper> build(UpgradeContext ctx) {
 
       List<TaskWrapper> tasks = new ArrayList<TaskWrapper>();
       for (String service : m_servicesToCheck) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
index e0bf754..f2e8521 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckGrouping.java
@@ -36,6 +36,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 
 /**
@@ -62,15 +63,6 @@ public class ServiceCheckGrouping extends Grouping {
     private Cluster m_cluster;
     private AmbariMetaInfo m_metaInfo;
 
-    /**
-     * Sets the helpers needed to determine service check validity
-     * @param cluster   the cluster
-     * @param metaInfo  the metainfo instance to determine command script availability
-     */
-    public void setHelpers(Cluster cluster, AmbariMetaInfo metaInfo) {
-      m_cluster = cluster;
-      m_metaInfo = metaInfo;
-    }
 
     @Override
     public void add(HostsType hostsType, String service, boolean forUpgrade, boolean clientOnly,
@@ -79,7 +71,10 @@ public class ServiceCheckGrouping extends Grouping {
     }
 
     @Override
-    public List<StageWrapper> build() {
+    public List<StageWrapper> build(UpgradeContext ctx) {
+      m_cluster = ctx.getCluster();
+      m_metaInfo = ctx.getAmbariMetaInfo();
+
       List<StageWrapper> result = new ArrayList<StageWrapper>();
 
       Map<String, Service> serviceMap = m_cluster.getServices();

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
index ee02a12..3bf9098 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapperBuilder.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.ambari.server.stack.HostsType;
+import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 
 /**
@@ -42,8 +43,10 @@ public abstract class StageWrapperBuilder {
 
   /**
    * Builds the stage wrappers.
+   * @param ctx the upgrade context
+   * @return a list of stages, never {@code null}
    */
-  public abstract List<StageWrapper> build();
+  public abstract List<StageWrapper> build(UpgradeContext ctx);
 
   /**
    * Consistently formats a string.

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
index 4cff683..139dbdb 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
@@ -114,6 +114,7 @@
     </group>
 
     <group name="CLIENTS" title="Client Components">
+      <service-check>false</service-check>
       <service name="HDFS">
         <component>HDFS_CLIENT</component>
       </service>

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/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 91a496e..9a06b8c 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
@@ -47,8 +47,10 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.dao.StageDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
@@ -68,6 +70,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.gson.Gson;
 import com.google.inject.Binder;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -196,6 +199,15 @@ public class UpgradeResourceProviderTest {
     UpgradeEntity entity = upgrades.get(0);
     assertEquals(cluster.getClusterId(), entity.getClusterId().longValue());
 
+    StageDAO stageDAO = injector.getInstance(StageDAO.class);
+    List<StageEntity> stageEntities = stageDAO.findByRequestId(entity.getRequestId());
+    Gson gson = new Gson();
+    for (StageEntity se : stageEntities) {
+      Map<String, String> map = (Map<String, String>) gson.fromJson(se.getCommandParamsStage(), Map.class);
+      assertTrue(map.containsKey("upgrade_direction"));
+      assertEquals("upgrade", map.get("upgrade_direction"));
+    }
+
     List<UpgradeGroupEntity> upgradeGroups = entity.getUpgradeGroups();
     assertEquals(4, upgradeGroups.size());
 
@@ -384,6 +396,7 @@ public class UpgradeResourceProviderTest {
 
   }
 
+  @SuppressWarnings("unchecked")
   @Test
   public void testDowngradeToBase() throws Exception {
     Cluster cluster = clusters.getCluster("c1");
@@ -429,6 +442,17 @@ public class UpgradeResourceProviderTest {
     assertEquals("2.1.1", entity.getFromVersion());
     assertEquals("2.2", entity.getToVersion());
 
+    StageDAO dao = injector.getInstance(StageDAO.class);
+    List<StageEntity> stages = dao.findByRequestId(entity.getRequestId());
+
+    Gson gson = new Gson();
+    for (StageEntity se : stages) {
+      Map<String, String> map = gson.fromJson(se.getCommandParamsStage(), Map.class);
+      assertTrue(map.containsKey("upgrade_direction"));
+      assertEquals("downgrade", map.get("upgrade_direction"));
+    }
+
+
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c649d0a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
index 3f7238b..518f0f2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
@@ -38,6 +38,7 @@ import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
 import org.apache.ambari.server.state.stack.UpgradePack;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.state.stack.upgrade.ManualTask;
 import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
 import org.easymock.EasyMock;
@@ -110,8 +111,10 @@ public class UpgradeHelperTest {
 
     makeCluster();
 
-    List<UpgradeGroupHolder> groups = m_upgradeHelper.createUpgrade(
-        m_masterHostResolver, upgrade, UPGRADE_VERSION);
+    UpgradeContext context = new UpgradeContext(m_masterHostResolver,
+        UPGRADE_VERSION, Direction.UPGRADE);
+
+    List<UpgradeGroupHolder> groups = m_upgradeHelper.createSequence(upgrade, context);
 
     assertEquals(5, groups.size());
 
@@ -143,8 +146,10 @@ public class UpgradeHelperTest {
 
     makeCluster();
 
-    List<UpgradeGroupHolder> groups = m_upgradeHelper.createDowngrade(
-        m_masterHostResolver, upgrade, DOWNGRADE_VERSION);
+    UpgradeContext context = new UpgradeContext(m_masterHostResolver,
+        DOWNGRADE_VERSION, Direction.DOWNGRADE);
+
+    List<UpgradeGroupHolder> groups = m_upgradeHelper.createSequence(upgrade, context);
 
     assertEquals(5, groups.size());
 
@@ -178,8 +183,10 @@ public class UpgradeHelperTest {
 
     makeCluster();
 
-    List<UpgradeGroupHolder> groups = m_upgradeHelper.createUpgrade(
-        m_masterHostResolver, upgrade, UPGRADE_VERSION);
+    UpgradeContext context = new UpgradeContext(m_masterHostResolver,
+        UPGRADE_VERSION, Direction.UPGRADE);
+
+    List<UpgradeGroupHolder> groups = m_upgradeHelper.createSequence(upgrade, context);
 
     assertEquals(1, groups.size());
     UpgradeGroupHolder group = groups.iterator().next();
@@ -196,8 +203,10 @@ public class UpgradeHelperTest {
 
     makeCluster();
 
-    List<UpgradeGroupHolder> groups = m_upgradeHelper.createUpgrade(
-        m_masterHostResolver, upgrade, UPGRADE_VERSION);
+    UpgradeContext context = new UpgradeContext(m_masterHostResolver,
+        UPGRADE_VERSION, Direction.UPGRADE);
+
+    List<UpgradeGroupHolder> groups = m_upgradeHelper.createSequence(upgrade, context);
 
     assertEquals(5, groups.size());
 
@@ -223,8 +232,10 @@ public class UpgradeHelperTest {
 
     makeCluster();
 
-    List<UpgradeGroupHolder> groups = m_upgradeHelper.createUpgrade(
-        m_masterHostResolver, upgrade, UPGRADE_VERSION);
+    UpgradeContext context = new UpgradeContext(m_masterHostResolver,
+        UPGRADE_VERSION, Direction.UPGRADE);
+
+    List<UpgradeGroupHolder> groups = m_upgradeHelper.createSequence(upgrade, context);
 
     assertEquals(7, groups.size());