ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nc...@apache.org
Subject ambari git commit: AMBARI-9603. RU: downgrade during Prepare Backups step causes issues (ncole)
Date Thu, 12 Feb 2015 20:53:39 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk ad620eee3 -> 87ddb4792


AMBARI-9603.  RU: downgrade during Prepare Backups step causes issues (ncole)


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

Branch: refs/heads/trunk
Commit: 87ddb4792734777cc9db0d74c2ac07789c672fda
Parents: ad620ee
Author: Nate Cole <ncole@hortonworks.com>
Authored: Thu Feb 12 15:04:07 2015 -0500
Committer: Nate Cole <ncole@hortonworks.com>
Committed: Thu Feb 12 15:09:01 2015 -0500

----------------------------------------------------------------------
 .../server/orm/entities/UpgradeItemEntity.java  |  4 +-
 .../apache/ambari/server/stack/HostsType.java   | 32 +++----
 .../ambari/server/stack/MasterHostResolver.java | 20 ++---
 .../ambari/server/state/UpgradeHelper.java      |  9 +-
 .../ambari/server/state/stack/UpgradePack.java  | 21 +++--
 .../state/stack/upgrade/ClusterGrouping.java    | 16 +++-
 .../state/stack/upgrade/ColocatedGrouping.java  | 26 +++---
 .../server/state/stack/upgrade/Grouping.java    | 31 ++++---
 .../state/stack/upgrade/TaskWrapperBuilder.java | 10 ++-
 .../stacks/HDP/2.2/upgrades/upgrade-2.2.xml     | 39 +++------
 .../AmbariManagementControllerTest.java         | 87 ++++++++++----------
 .../internal/UpgradeResourceProviderTest.java   | 76 ++++++++++++++---
 .../ambari/server/state/UpgradeHelperTest.java  | 13 ++-
 .../server/state/stack/UpgradePackTest.java     | 31 ++++++-
 .../HDP/2.1.1/upgrades/upgrade_direction.xml    | 70 ++++++++++++++++
 .../stacks/HDP/2.1.1/upgrades/upgrade_test.xml  |  2 +
 16 files changed, 327 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeItemEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeItemEntity.java
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeItemEntity.java
index f9336ef..fe9508b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeItemEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeItemEntity.java
@@ -27,8 +27,6 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
@@ -61,7 +59,7 @@ public class UpgradeItemEntity {
   private String hosts = null;
 
   @Basic
-  @Column(name = "tasks")
+  @Column(name = "tasks", length=4096)
   private String tasks = null;
 
   @Basic

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/main/java/org/apache/ambari/server/stack/HostsType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/HostsType.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/HostsType.java
index 556e5fa..55313d5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/HostsType.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/HostsType.java
@@ -19,32 +19,36 @@
 package org.apache.ambari.server.stack;
 
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Set;
 
 import org.apache.ambari.server.state.ServiceComponentHost;
 
 /**
- * Wrapper around a collection of hosts that may have either a Master or Secondary host.
+ * Wrapper around a collection of hosts for components.  Some components
+ * also have master/secondary designators.
  */
 public class HostsType {
 
-  public String master;
+  /**
+   * The master host, if any.
+   */
+  public String master = null;
 
-  public String secondary;
+  /**
+   * The secondary host, if any.
+   */
+  public String secondary = null;
 
   /**
-   * Ordered collection of hosts.
+   * Ordered collection of hosts.  This represents all hosts where an upgrade
+   * or downgrade must occur.  For an upgrade, all hosts are set.  For a downgrade,
+   * this list may be a subset of all hosts where the downgrade MUST be executed.
+   * That is to say, a downgrade only occurs where the current version is not
+   * the target version.
    */
-  public Set<String> hosts;
+  public LinkedHashSet<String> hosts = new LinkedHashSet<String>();
 
-  public List<ServiceComponentHost> unhealthy;
+  public List<ServiceComponentHost> unhealthy = new ArrayList<ServiceComponentHost>();
 
-  public HostsType () {
-    master = null;
-    secondary = null;
-    hosts = new HashSet<String>();
-    unhealthy = new ArrayList<ServiceComponentHost>();
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
index 0800c91..5800647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
@@ -120,7 +120,7 @@ public class MasterHostResolver {
     }
 
     HostsType hostsType = new HostsType();
-    hostsType.hosts = componentHosts;
+    hostsType.hosts.addAll(componentHosts);
 
     Service s = Service.OTHER;
     try {
@@ -134,7 +134,7 @@ public class MasterHostResolver {
         case HDFS:
           if (componentName.equalsIgnoreCase("NAMENODE")) {
             if (componentHosts.size() != 2) {
-              return hostsType;
+              return filterSameVersion(hostsType, serviceName, componentName);
             }
 
             Map<Status, String> pair = getNameNodePair();
@@ -144,31 +144,27 @@ public class MasterHostResolver {
             } else {
               hostsType.master = componentHosts.iterator().next();
             }
-          } else {
-            hostsType = filterSameVersion(hostsType, serviceName, componentName);
           }
           break;
         case YARN:
           if (componentName.equalsIgnoreCase("RESOURCEMANAGER")) {
             resolveResourceManagers(getCluster(), hostsType);
-          } else {
-            hostsType = filterSameVersion(hostsType, serviceName, componentName);
           }
           break;
         case HBASE:
           if (componentName.equalsIgnoreCase("HBASE_MASTER")) {
             resolveHBaseMasters(getCluster(), hostsType);
-          } else {
-            hostsType = filterSameVersion(hostsType, serviceName, componentName);
           }
           break;
-        case OTHER:
-          hostsType = filterSameVersion(hostsType, serviceName, componentName);
+        default:
           break;
       }
     } catch (Exception err) {
       LOG.error("Unable to get master and hosts for Component " + componentName + ". Error:
" + err.getMessage(), err);
     }
+
+    hostsType = filterSameVersion(hostsType, serviceName, componentName);
+
     return hostsType;
   }
 
@@ -190,7 +186,7 @@ public class MasterHostResolver {
 
       // !!! not really a fan of passing these around
       List<ServiceComponentHost> unhealthy = new ArrayList<ServiceComponentHost>();
-      Set<String> toUpgrade = new LinkedHashSet<String>();
+      LinkedHashSet<String> toUpgrade = new LinkedHashSet<String>();
 
       for (String host : hostsType.hosts) {
         ServiceComponentHost sch = sc.getServiceComponentHost(host);
@@ -271,7 +267,7 @@ public class MasterHostResolver {
   }
 
   private void resolveResourceManagers(Cluster cluster, HostsType hostType) throws MalformedURLException
{
-    Set<String> orderedHosts = new LinkedHashSet<String>(hostType.hosts);
+    LinkedHashSet<String> orderedHosts = new LinkedHashSet<String>(hostType.hosts);
 
     // IMPORTANT, for RM, only the master returns jmx
     String rmWebAppAddress = m_configHelper.getValueFromDesiredConfigurations(cluster, ConfigHelper.YARN_SITE,
"yarn.resourcemanager.webapp.address");

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 f7a5276..76df049 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,7 +17,6 @@
  */
 package org.apache.ambari.server.state;
 
-import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -194,7 +193,7 @@ public class UpgradeHelper {
     Map<String, Map<String, ProcessingComponent>> allTasks = upgradePack.getTasks();
     List<UpgradeGroupHolder> groups = new ArrayList<UpgradeGroupHolder>();
 
-    for (Grouping group : upgradePack.getGroups(context.getDirection().isUpgrade())) {
+    for (Grouping group : upgradePack.getGroups(context.getDirection())) {
 
       UpgradeGroupHolder groupHolder = new UpgradeGroupHolder();
       groupHolder.name = group.name;
@@ -246,17 +245,15 @@ public class UpgradeHelper {
           // Special case for NAMENODE
           if (service.serviceName.equalsIgnoreCase("HDFS") && component.equalsIgnoreCase("NAMENODE"))
{
             // !!! revisit if needed
-            if (hostsType.master != null && hostsType.secondary != null) {
+            if (!hostsType.hosts.isEmpty() && hostsType.master != null &&
hostsType.secondary != null) {
               // The order is important, first do the standby, then the active namenode.
-              Set<String> order = new LinkedHashSet<String>();
+              LinkedHashSet<String> order = new LinkedHashSet<String>();
 
               order.add(hostsType.secondary);
               order.add(hostsType.master);
 
               // Override the hosts with the ordered collection
               hostsType.hosts = order;
-            } else {
-                throw new AmbariException(MessageFormat.format("Could not find active and
standby namenodes using hosts: {0}", StringUtils.join(hostsType.hosts, ", ").toString()));
             }
 
             builder.add(context, hostsType, service.serviceName,

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
index cade1b0..b10f3f7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
@@ -32,6 +32,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 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.ServiceCheckGrouping;
 import org.apache.ambari.server.state.stack.upgrade.Task;
@@ -70,12 +71,22 @@ public class UpgradePack {
   }
 
   /**
-   * Gets the groups defined for the upgrade pack
-   * @param upgrade {@code true} if returning the groups in proper order for an upgrade
+   * Gets the groups defined for the upgrade pack.  If a direction is defined
+   * for a group, it must match the supplied direction to be returned
+   * @param direction the direction to return the ordered groups
    * @return the list of groups
    */
-  public List<Grouping> getGroups(boolean upgrade) {
-    return upgrade ? groups : getDowngradeGroups();
+  public List<Grouping> getGroups(Direction direction) {
+    List<Grouping> list = direction.isUpgrade() ? groups : getDowngradeGroups();
+
+    List<Grouping> checked = new ArrayList<Grouping>();
+    for (Grouping group : list) {
+      if (null == group.intendedDirection || direction == group.intendedDirection) {
+        checked.add(group);
+      }
+    }
+
+    return checked;
   }
 
   /**
@@ -219,7 +230,5 @@ public class UpgradePack {
     @XmlElementWrapper(name="post-downgrade")
     @XmlElement(name="task")
     public List<Task> postDowngradeTasks;
-
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 bf7a068..c0ae92a 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
@@ -53,7 +53,7 @@ public class ClusterGrouping extends Grouping {
    * Stages against a Service and Component, or the Server
    */
   @XmlElement(name="execute-stage")
-  private List<ExecuteStage> executionStages;
+  public List<ExecuteStage> executionStages;
 
   @XmlTransient
   private ClusterBuilder m_builder = new ClusterBuilder();
@@ -64,13 +64,20 @@ public class ClusterGrouping extends Grouping {
   }
 
 
-  private static class ExecuteStage {
+  /**
+   * Represents a single-stage execution that happens as part of a cluster-wide
+   * upgrade or downgrade.
+   */
+  public static class ExecuteStage {
     @XmlAttribute(name="title")
     public String title;
 
     @XmlAttribute(name="id")
     public String id;
 
+    @XmlElement(name="direction")
+    public Direction intendedDirection = null;
+
     /**
      * Optional service name, can be ""
      */
@@ -105,6 +112,11 @@ public class ClusterGrouping extends Grouping {
 
       if (executionStages != null) {
         for (ExecuteStage execution : executionStages) {
+          if (null != execution.intendedDirection &&
+              execution.intendedDirection != ctx.getDirection()) {
+            continue;
+          }
+
           Task task = execution.task;
 
           StageWrapper wrapper = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 7c001d9..55a6aa4 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
@@ -64,7 +64,7 @@ public class ColocatedGrouping extends Grouping {
 
 
     private MultiHomedBuilder(Batch batch, boolean serviceCheck) {
-      this.m_batch = batch;
+      m_batch = batch;
       m_serviceCheck = serviceCheck;
     }
 
@@ -81,7 +81,7 @@ public class ColocatedGrouping extends Grouping {
       for (String host : hostsType.hosts) {
         // This class required inserting a single host into the collection
         HostsType singleHostsType = new HostsType();
-        singleHostsType.hosts = Collections.singleton(host);
+        singleHostsType.hosts.add(host);
 
         Map<String, List<TaskProxy>> targetMap = ((i++) < count) ? initialBatch
: finalBatches;
         List<TaskProxy> targetList = targetMap.get(host);
@@ -146,18 +146,20 @@ public class ColocatedGrouping extends Grouping {
         LOG.debug("RU final: {}", finalBatches);
       }
 
-      results.addAll(fromProxies(ctx.getDirection(), initialBatch));
+      List<StageWrapper> befores = fromProxies(ctx.getDirection(), initialBatch);
+      results.addAll(befores);
 
-      // !!! TODO when manual tasks are ready
-      ManualTask task = new ManualTask();
-      task.summary = m_batch.summary;
-      task.message = m_batch.message;
+      if (!befores.isEmpty()) {
+        ManualTask task = new ManualTask();
+        task.summary = m_batch.summary;
+        task.message = m_batch.message;
 
-      StageWrapper wrapper = new StageWrapper(
-          StageWrapper.Type.SERVER_SIDE_ACTION,
-          "Validate Partial " + ctx.getDirection().getText(true),
-          new TaskWrapper(null, null, Collections.<String>emptySet(), task));
-      results.add(wrapper);
+        StageWrapper wrapper = new StageWrapper(
+            StageWrapper.Type.SERVER_SIDE_ACTION,
+            "Validate Partial " + ctx.getDirection().getText(true),
+            new TaskWrapper(null, null, Collections.<String>emptySet(), task));
+        results.add(wrapper);
+      }
 
       results.addAll(fromProxies(ctx.getDirection(), finalBatches));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 ec517d9..a1e1fcd 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
@@ -57,6 +57,9 @@ public class Grouping {
   @XmlElement(name="service-check", defaultValue="true")
   public boolean performServiceCheck = true;
 
+  @XmlElement(name="direction")
+  public Direction intendedDirection = null;
+
 
   /**
    * Gets the default builder.
@@ -93,12 +96,14 @@ public class Grouping {
       for (TaskBucket bucket : buckets) {
         List<TaskWrapper> preTasks = TaskWrapperBuilder.getTaskList(service, pc.name,
hostsType, bucket.tasks);
         Set<String> preTasksEffectiveHosts = TaskWrapperBuilder.getEffectiveHosts(preTasks);
-        StageWrapper stage = new StageWrapper(
-            bucket.type,
-            getStageText("Preparing", ctx.getComponentDisplay(service, pc.name), preTasksEffectiveHosts),
-            preTasks
-            );
-        m_stages.add(stage);
+        if (!preTasksEffectiveHosts.isEmpty()) {
+          StageWrapper stage = new StageWrapper(
+              bucket.type,
+              getStageText("Preparing", ctx.getComponentDisplay(service, pc.name), preTasksEffectiveHosts),
+              preTasks
+              );
+          m_stages.add(stage);
+        }
       }
 
       // !!! FIXME upgrade definition have only one step, and it better be a restart
@@ -119,12 +124,14 @@ public class Grouping {
       for (TaskBucket bucket : buckets) {
         List<TaskWrapper> postTasks = TaskWrapperBuilder.getTaskList(service, pc.name,
hostsType, bucket.tasks);
         Set<String> postTasksEffectiveHosts = TaskWrapperBuilder.getEffectiveHosts(postTasks);
-        StageWrapper stage = new StageWrapper(
-            bucket.type,
-            getStageText("Completing", ctx.getComponentDisplay(service, pc.name), postTasksEffectiveHosts),
-            postTasks
-            );
-        m_stages.add(stage);
+        if (!postTasksEffectiveHosts.isEmpty()) {
+          StageWrapper stage = new StageWrapper(
+              bucket.type,
+              getStageText("Completing", ctx.getComponentDisplay(service, pc.name), postTasksEffectiveHosts),
+              postTasks
+              );
+          m_stages.add(stage);
+        }
       }
 
       if (!clientOnly) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/TaskWrapperBuilder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/TaskWrapperBuilder.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/TaskWrapperBuilder.java
index 81ec2ff..bb0b8d6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/TaskWrapperBuilder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/TaskWrapperBuilder.java
@@ -17,13 +17,17 @@
  */
 package org.apache.ambari.server.state.stack.upgrade;
 
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.ambari.server.stack.HostsType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.text.MessageFormat;
-import java.util.*;
-
 
 /**
  * Generates a collection of tasks that need to run on a set of hosts during an upgarde.

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 2e00b3e..5305b1f 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
@@ -23,7 +23,7 @@
   <order>
 
     <group xsi:type="cluster" name="PRE_CLUSTER" title="Prepare Backups">
-
+      <direction>UPGRADE</direction>
       <execute-stage service="HDFS" component="NAMENODE" title="Pre Upgrade HDFS">
         <task xsi:type="execute" hosts="master">
           <script>scripts/namenode.py</script>
@@ -31,20 +31,20 @@
         </task>
       </execute-stage>
 
-      <execute-stage service="HBASE" component="HBASE_MASTER" title="Pre Upgrade HBASE">
+      <execute-stage service="HBASE" component="HBASE_MASTER" title="Pre Upgrade HBase">
         <task xsi:type="execute" hosts="master">
           <script>scripts/hbase_upgrade.py</script>
           <function>snapshot</function>
         </task>
       </execute-stage>
 
-      <execute-stage service="HIVE" component="HIVE_METASTORE" title="Pre Upgrade HIVE">
+      <execute-stage service="HIVE" component="HIVE_METASTORE" title="Pre Upgrade Hive">
         <task xsi:type="manual">
-          <message>Backup the Hive Metastore database located on the following host(s):
{{hosts.all}}</message>
+          <message>Backup the Hive Metastore database located on the following host(s):
{{hosts.all}}.  During the upgrade process, you will be instructed when it is time to upgrade
the Hive Metastore database.  To prepare, review the README documentation at /usr/hdp/{{version}}/hive/scripts/metastore/upgrade
for when you are asked to perform this manual step (during the Hive stage of upgrade).  Do
not upgrade the database at this time.  You will be prompted when to perform the database
upgrade.</message>
         </task>
       </execute-stage>
 
-      <execute-stage service="OOZIE" component="OOZIE_SERVER" title="Pre Upgrade OOZIE">
+      <execute-stage service="OOZIE" component="OOZIE_SERVER" title="Pre Upgrade Oozie">
         <task xsi:type="manual">
           <message>Backup the Oozie Server database on {{oozie-env/oozie_hostname}}</message>
         </task>
@@ -89,6 +89,7 @@
     </group>
     
     <group name="SERVICE_CHECK" title="All Service Checks" xsi:type="service-check">
+      <direction>UPGRADE</direction>
       <priority>
         <service>HDFS</service>
         <service>MAPREDUCE2</service>
@@ -119,6 +120,7 @@
     </group>
     
     <group name="SERVICE_CHECK" title="All Service Checks" xsi:type="service-check">
+      <direction>UPGRADE</direction>
       <priority>
         <service>HDFS</service>
         <service>YARN</service>
@@ -191,6 +193,7 @@
     </group>
 
     <group name="SERVICE_CHECK" title="All Service Checks" xsi:type="service-check">
+      <direction>UPGRADE</direction>
       <priority>
         <service>HDFS</service>
         <service>YARN</service>
@@ -247,8 +250,9 @@
       </execute-stage>
       
       <execute-stage title="Confirm Finalize">
+        <direction>UPGRADE</direction>
         <task xsi:type="manual">
-          <message>Please confirm you are ready to finalize</message>
+          <message>Please confirm you are ready to finalize.</message>
         </task>
       </execute-stage>
 
@@ -268,28 +272,6 @@
   <processing>
     <service name="ZOOKEEPER">
       <component name="ZOOKEEPER_SERVER">
-        <!-- TODO, optimization
-        <pre-upgrade>
-          Find the leader by running
-          echo stat | nc localhost 2181
-          on the ZK nodes until one of them replies with a value (standalone or replicated).
-          Store that leader, and perform the upgrade on the leader last, this is only an
optimization and is optional.
-        </pre-upgrade>
-        -->
-
-        <!-- ZK Server Restart (or Start, implicitly) must do the following:
-        Before continuing to the next ZK host, make sure that a quorum is established.
-        Start the shell, /usr/hdp/current/zookeeper-client/bin/zkCli.sh
-        Then run,
-        $ create /zk_test mydata
-        $ ls /
-        [hiveserver2, zookeeper, zk_test]
-
-        Finally, delete it,
-        $ delete /zk_test
-
-        $ quit
-        -->
         <upgrade>
           <task xsi:type="restart" />
         </upgrade>
@@ -437,6 +419,7 @@
             <message>Consult the README documentation at /usr/hdp/{{version}}/hive/scripts/metastore/upgrade
to correctly upgrade the Hive Metastore database. This database upgrade should be performed
on the following host(s): {{hosts.all}}</message>
           </task>
         </pre-upgrade>
+        <pre-downgrade />
         <upgrade>
           <task xsi:type="restart" />
         </upgrade>

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 7df7b7b..2833f2c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -18,13 +18,45 @@
 
 package org.apache.ambari.server.controller;
 
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.persist.PersistService;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Type;
+import java.net.ConnectException;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+
 import junit.framework.Assert;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -109,41 +141,12 @@ import org.junit.rules.ExpectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.persistence.EntityManager;
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.lang.reflect.Type;
-import java.net.ConnectException;
-import java.net.MalformedURLException;
-import java.net.UnknownHostException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
 
 public class AmbariManagementControllerTest {
 
@@ -6912,7 +6915,7 @@ public class AmbariManagementControllerTest {
     Assert.assertEquals(1, responsesWithParams.size());
     StackVersionResponse resp = responsesWithParams.iterator().next();
     assertNotNull(resp.getUpgradePacks());
-    assertEquals(3, resp.getUpgradePacks().size());
+    assertEquals(4, resp.getUpgradePacks().size());
     assertTrue(resp.getUpgradePacks().contains("upgrade_test"));
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 4c8cfc4..ef4bd82 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
@@ -58,6 +58,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -155,6 +156,7 @@ public class UpgradeResourceProviderTest {
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "6.3");
     host.setHostAttributes(hostAttributes);
+    host.setState(HostState.HEALTHY);
     host.persist();
 
     clusters.mapHostToCluster("h1", "c1");
@@ -179,7 +181,7 @@ public class UpgradeResourceProviderTest {
     injector = null;
   }
 
-  public org.apache.ambari.server.controller.spi.RequestStatus testCreateResources() throws
Exception {
+  private org.apache.ambari.server.controller.spi.RequestStatus testCreateResources() throws
Exception {
 
     Cluster cluster = clusters.getCluster("c1");
 
@@ -211,7 +213,7 @@ public class UpgradeResourceProviderTest {
     }
 
     List<UpgradeGroupEntity> upgradeGroups = entity.getUpgradeGroups();
-    assertEquals(4, upgradeGroups.size());
+    assertEquals(3, upgradeGroups.size());
 
     UpgradeGroupEntity group = upgradeGroups.get(1);
     assertEquals(4, group.getItems().size());
@@ -232,15 +234,15 @@ public class UpgradeResourceProviderTest {
 
     List<Stage> stages = am.getRequestStatus(requests.get(0).longValue());
 
-    assertEquals(9, stages.size());
+    assertEquals(8, stages.size());
 
     List<HostRoleCommand> tasks = am.getRequestTasks(requests.get(0).longValue());
     // same number of tasks as stages here
-    assertEquals(9, tasks.size());
+    assertEquals(8, tasks.size());
 
     Set<Long> slaveStageIds = new HashSet<Long>();
 
-    UpgradeGroupEntity coreSlavesGroup = upgradeGroups.get(2);
+    UpgradeGroupEntity coreSlavesGroup = upgradeGroups.get(1);
 
     for (UpgradeItemEntity itemEntity : coreSlavesGroup.getItems()) {
       slaveStageIds.add(itemEntity.getStageId());
@@ -304,7 +306,7 @@ public class UpgradeResourceProviderTest {
     ResourceProvider upgradeGroupResourceProvider = new UpgradeGroupResourceProvider(amc);
     resources = upgradeGroupResourceProvider.getResources(request, predicate);
 
-    assertEquals(4, resources.size());
+    assertEquals(3, resources.size());
     res = resources.iterator().next();
     assertNotNull(res.getPropertyValue("UpgradeGroup/status"));
     assertNotNull(res.getPropertyValue("UpgradeGroup/group_id"));
@@ -344,11 +346,11 @@ public class UpgradeResourceProviderTest {
 
     upgradeItemResourceProvider = new UpgradeItemResourceProvider(amc);
     resources = upgradeItemResourceProvider.getResources(request, predicate);
-    assertEquals(1, resources.size());
+    assertEquals(2, resources.size());
     res = resources.iterator().next();
 
-    assertEquals("Validate Partial Upgrade", res.getPropertyValue("UpgradeItem/context"));
-    assertTrue(res.getPropertyValue("UpgradeItem/text").toString().startsWith("Please run"));
+    assertEquals("Confirm Finalize", res.getPropertyValue("UpgradeItem/context"));
+    assertTrue(res.getPropertyValue("UpgradeItem/text").toString().startsWith("Please confirm"));
   }
 
   @Test
@@ -394,9 +396,9 @@ public class UpgradeResourceProviderTest {
     assertEquals(cluster.getClusterId(), entity.getClusterId().longValue());
 
     List<UpgradeGroupEntity> upgradeGroups = entity.getUpgradeGroups();
-    assertEquals(4, upgradeGroups.size());
+    assertEquals(3, upgradeGroups.size());
 
-    UpgradeGroupEntity group = upgradeGroups.get(2);
+    UpgradeGroupEntity group = upgradeGroups.get(1);
     assertEquals("ZOOKEEPER", group.getName());
     assertEquals(3, group.getItems().size());
 
@@ -484,6 +486,58 @@ public class UpgradeResourceProviderTest {
 
   }
 
+  @Test
+  public void testDirectionUpgrade() throws Exception {
+    Cluster cluster = clusters.getCluster("c1");
+
+    RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
+    repoVersionEntity.setDisplayName("My New Version 3");
+    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.setStack("HDP-2.1.1");
+    repoVersionEntity.setUpgradePackage("upgrade_direction");
+    repoVersionEntity.setVersion("2.2.2.3");
+    repoVersionDao.create(repoVersionEntity);
+
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1");
+    requestProps.put(UpgradeResourceProvider.UPGRADE_VERSION, "2.2.2.3");
+
+    ResourceProvider upgradeResourceProvider = createProvider(amc);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps),
null);
+    upgradeResourceProvider.createResources(request);
+
+    List<UpgradeEntity> upgrades = upgradeDao.findUpgrades(cluster.getClusterId());
+    assertEquals(1, upgrades.size());
+
+    UpgradeEntity upgrade = upgrades.get(0);
+    Long id = upgrade.getRequestId();
+    assertEquals(3, upgrade.getUpgradeGroups().size());
+    UpgradeGroupEntity group = upgrade.getUpgradeGroups().get(2);
+    assertEquals(1, group.getItems().size());
+
+    requestProps.put(UpgradeResourceProvider.UPGRADE_VERSION, "2.2");
+    requestProps.put(UpgradeResourceProvider.UPGRADE_FROM_VERSION, "2.2.2.3");
+    requestProps.put(UpgradeResourceProvider.UPGRADE_FORCE_DOWNGRADE, "true");
+
+    request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    upgradeResourceProvider.createResources(request);
+
+    upgrades = upgradeDao.findUpgrades(cluster.getClusterId());
+    assertEquals(2, upgrades.size());
+
+    upgrade = null;
+    for (UpgradeEntity u : upgrades) {
+      if (!u.getRequestId().equals(id)) {
+        upgrade = u;
+      }
+    }
+    assertNotNull(upgrade);
+    assertEquals("Downgrade groups reduced from 3 to 2", 2, upgrade.getUpgradeGroups().size());
+    group = upgrade.getUpgradeGroups().get(1);
+    assertEquals("Execution items increased from 1 to 2", 2, group.getItems().size());
+  }
+
 
   /**
    * @param amc

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/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 74b2495..a708dac 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
@@ -150,7 +150,6 @@ public class UpgradeHelperTest {
     }
     assertTrue("Expected to find replaced text for Upgrading", found);
 
-
     UpgradeGroupHolder group = groups.get(1);
     // check that the display name is being used
     assertTrue(group.items.get(1).getText().contains("ZooKeeper1 Server2"));
@@ -559,30 +558,30 @@ public class UpgradeHelperTest {
     }, null);
 
     HostsType type = new HostsType();
-    type.hosts = new HashSet<String>(Arrays.asList("h1", "h2", "h3"));
+    type.hosts.addAll(Arrays.asList("h1", "h2", "h3"));
     expect(m_masterHostResolver.getMasterAndHosts("ZOOKEEPER", "ZOOKEEPER_SERVER")).andReturn(type).anyTimes();
 
     type = new HostsType();
-    type.hosts = new HashSet<String>(Arrays.asList("h1", "h2"));
+    type.hosts.addAll(Arrays.asList("h1", "h2"));
     type.master = "h1";
     type.secondary = "h2";
     expect(m_masterHostResolver.getMasterAndHosts("HDFS", "NAMENODE")).andReturn(type).anyTimes();
 
     type = new HostsType();
     if (clean) {
-      type.hosts = new HashSet<String>(Arrays.asList("h2", "h3", "h4"));
+      type.hosts.addAll(Arrays.asList("h2", "h3", "h4"));
     } else {
       type.unhealthy = Collections.singletonList(sch);
-      type.hosts = new HashSet<String>(Arrays.asList("h2", "h3"));
+      type.hosts.addAll(Arrays.asList("h2", "h3"));
     }
     expect(m_masterHostResolver.getMasterAndHosts("HDFS", "DATANODE")).andReturn(type).anyTimes();
 
     type = new HostsType();
-    type.hosts = new HashSet<String>(Arrays.asList("h2"));
+    type.hosts.addAll(Arrays.asList("h2"));
     expect(m_masterHostResolver.getMasterAndHosts("YARN", "RESOURCEMANAGER")).andReturn(type).anyTimes();
 
     type = new HostsType();
-    type.hosts = new HashSet<String>(Arrays.asList("h1", "h3"));
+    type.hosts.addAll(Arrays.asList("h1", "h3"));
     expect(m_masterHostResolver.getMasterAndHosts("YARN", "NODEMANAGER")).andReturn(type).anyTimes();
 
     expect(m_masterHostResolver.getMasterAndHosts("HIVE", "HIVE_SERVER")).andReturn(

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
index f4aa92d..b37c0a7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
@@ -32,6 +32,9 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 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.ClusterGrouping.ExecuteStage;
+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.RestartTask;
 import org.apache.ambari.server.state.stack.upgrade.Task;
@@ -167,20 +170,44 @@ public class UpgradePackTest {
         "POST_CLUSTER");
 
     int i = 0;
-    List<Grouping> groups = up.getGroups(true);
+    List<Grouping> groups = up.getGroups(Direction.UPGRADE);
     for (Grouping g : groups) {
       assertEquals(expected_up.get(i), g.name);
       i++;
     }
 
     i = 0;
-    groups = up.getGroups(false);
+    groups = up.getGroups(Direction.DOWNGRADE);
     for (Grouping g : groups) {
       assertEquals(expected_down.get(i), g.name);
       i++;
     }
   }
 
+  @Test
+  public void testDirection() throws Exception {
+    Map<String, UpgradePack> upgrades = ambariMetaInfo.getUpgradePacks("HDP", "2.1.1");
+    assertTrue(upgrades.size() > 0);
+    assertTrue(upgrades.containsKey("upgrade_direction"));
+
+    UpgradePack up = upgrades.get("upgrade_direction");
+
+    List<Grouping> groups = up.getGroups(Direction.UPGRADE);
+    assertEquals(3, groups.size());
+    Grouping group = groups.get(2);
+    assertEquals(ClusterGrouping.class, group.getClass());
+
+    ClusterGrouping cluster_group = (ClusterGrouping) groups.get(2);
+    List<ExecuteStage> stages = cluster_group.executionStages;
+    assertEquals(2, stages.size());
+    assertNotNull(stages.get(0).intendedDirection);
+    assertEquals(Direction.DOWNGRADE, stages.get(0).intendedDirection);
+
+    groups = up.getGroups(Direction.DOWNGRADE);
+    assertEquals(2, groups.size());
+    assertEquals(ClusterGrouping.class, groups.get(1).getClass());
+  }
+
 
   private int indexOf(Map<String, ?> map, String keyToFind) {
     int result = -1;

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_direction.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_direction.xml
b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_direction.xml
new file mode 100644
index 0000000..22a4ea7
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_direction.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<upgrade xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <target>2.2.*</target>
+  
+  <order>
+    <group name="ZOOKEEPER" title="Zookeeper">
+      <service name="ZOOKEEPER">
+        <component>ZOOKEEPER_SERVER</component>
+        <component>ZOOKEEPER_CLIENT</component>
+      </service>
+    </group>
+    
+    <group name="SERVICE_CHECK_1" title="Service Checks" xsi:type="service-check">
+      <direction>UPGRADE</direction>
+      <priority>
+        <service>HDFS</service>
+        <service>YARN</service>
+      </priority>
+    </group>
+    
+    <group xsi:type="cluster" name="POST_CLUSTER" title="Finalize Upgrade">
+      <execute-stage title="Direction Downgrade Only">
+        <direction>DOWNGRADE</direction>
+        <task xsi:type="manual">
+          <message>this is downgrade message</message>
+        </task>
+      </execute-stage>
+      <execute-stage title="Save Cluster State" service="" component="">
+        <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction">
+        </task>
+      </execute-stage>
+    </group>
+  </order>
+  
+  <processing>
+    <service name="ZOOKEEPER">
+      <component name="ZOOKEEPER_SERVER">
+        <pre-upgrade>
+          <task xsi:type="manual">
+            <summary>SUMMARY OF PREPARE</summary>
+            <message>This is a manual task with a placeholder of {{foo/bar}}</message>
+          </task>
+        </pre-upgrade>
+        <upgrade>
+          <task xsi:type="restart" />
+        </upgrade>
+        <post-upgrade>
+          <task xsi:type="configure" />
+        </post-upgrade>
+      </component>
+    </service>
+  </processing>
+  
+</upgrade>

http://git-wip-us.apache.org/repos/asf/ambari/blob/87ddb479/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
index 3dd7f2f..a9b1cad 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
@@ -43,6 +43,8 @@
     </group>
   
     <group name="ZOOKEEPER" title="Zookeeper">
+      <skippable>true</skippable>
+      <allow-retry>false</allow-retry>
       <service name="ZOOKEEPER">
         <component>ZOOKEEPER_SERVER</component>
         <component>ZOOKEEPER_CLIENT</component>


Mime
View raw message