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

[7/9] ambari git commit: AMBARI-13392. Stop-and-Start Upgrade: Merge branch branch-dev-stop-all-upgrade to branch-2.1 for feature Stop-the-World Upgrade, aka Express Upgrade (alejandro, dlysnichenko, Dmytro Grinenko)

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/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 5b65732..5a8031b 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
@@ -22,6 +22,7 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -36,6 +37,7 @@ 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;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 /**
  * Represents an upgrade pack.
@@ -44,16 +46,37 @@ import org.apache.ambari.server.state.stack.upgrade.Task;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class UpgradePack {
 
+  /**
+   * Name of the file without the extension, such as upgrade-2.2
+   */
+  private String name;
+
   @XmlElement(name="target")
   private String target;
 
   @XmlElement(name="target-stack")
   private String targetStack;
 
+  @XmlElement(name="type", defaultValue="rolling")
+  private UpgradeType type;
+
+  @XmlElementWrapper(name="upgrade-path")
+  @XmlElement(name="intermediate-stack")
+  private List<IntermediateStack> intermediateStacks;
+
   @XmlElementWrapper(name="order")
   @XmlElement(name="group")
   private List<Grouping> groups;
 
+  @XmlElementWrapper(name="prerequisite-checks")
+  @XmlElement(name="check", type=String.class)
+  private List<String> prerequisiteChecks = new ArrayList<String>();
+
+  /**
+   * In the case of a rolling upgrade, will specify processing logic for a particular component.
+   * NonRolling upgrades are simpler so the "processing" is embedded into the  group's "type", which is a function like
+   * "stop" or "start".
+   */
   @XmlElementWrapper(name="processing")
   @XmlElement(name="service")
   private List<ProcessingService> processing;
@@ -81,7 +104,13 @@ public class UpgradePack {
   @XmlTransient
   private boolean m_resolvedGroups = false;
 
+  public String getName() {
+    return name;
+  }
 
+  public void setName(String name) {
+    this.name = name;
+  }
   /**
    * @return the target version for the upgrade pack
    */
@@ -116,29 +145,66 @@ public class UpgradePack {
   }
 
   /**
-   * 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 type of upgrade, e.g., "ROLLING" or "NON_ROLLING"
+   */
+  public UpgradeType getType() {
+    return type;
+  }
+
+  /**
+   * @return the preCheck name, e.g. "CheckDescription"
+   */
+  public List<String> getPrerequisiteChecks() {
+    return new ArrayList<String>(prerequisiteChecks);
+  }
+
+  /**
+   * @return a list for intermediate stacks for cross-stack upgrade, or null if no any
+   */
+  public List<IntermediateStack> getIntermediateStacks() {
+    return intermediateStacks;
+  }
+
+  /**
+   * 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(Direction direction) {
-    List<Grouping> list = direction.isUpgrade() ? groups : getDowngradeGroups();
+    List<Grouping> list = new ArrayList<Grouping>();
+    if (direction.isUpgrade()) {
+      list = groups;
+    } else {
+      if (type == UpgradeType.ROLLING) {
+        list = getDowngradeGroupsForRolling();
+      } else if (type == UpgradeType.NON_ROLLING) {
+        list = getDowngradeGroupsForNonrolling();
+      }
+    }
 
     List<Grouping> checked = new ArrayList<Grouping>();
     for (Grouping group : list) {
       if (null == group.intendedDirection || direction == group.intendedDirection) {
         checked.add(group);
       }
-
     }
 
     return checked;
   }
 
+  public boolean canBeApplied(String targetVersion){
+    // check that upgrade pack can be applied to selected stack
+    // converting 2.2.*.* -> 2\.2(\.\d+)?(\.\d+)?(-\d+)?
+
+    String regexPattern = getTarget().replaceAll("\\.", "\\\\."); // . -> \.
+    regexPattern = regexPattern.replaceAll("\\\\\\.\\*", "(\\\\\\.\\\\d+)?"); // \.* -> (\.\d+)?
+    regexPattern = regexPattern.concat("(-\\d+)?");
+    return Pattern.matches(regexPattern, targetVersion);
+  }
+
   /**
-   * Calculates the group orders when performing a downgrade
+   * Calculates the group orders when performing a rolling downgrade
    * <ul>
    *   <li>ClusterGroupings must remain at the same positions (first/last).</li>
    *   <li>When there is a ServiceCheck group, it must ALWAYS follow the same</li>
@@ -169,7 +235,7 @@ public class UpgradePack {
    * </ol>
    * @return the list of groups, reversed appropriately for a downgrade.
    */
-  private List<Grouping> getDowngradeGroups() {
+  private List<Grouping> getDowngradeGroupsForRolling() {
     List<Grouping> reverse = new ArrayList<Grouping>();
 
     int idx = 0;
@@ -199,6 +265,17 @@ public class UpgradePack {
     return reverse;
   }
 
+  private List<Grouping> getDowngradeGroupsForNonrolling() {
+    throw new UnsupportedOperationException("TODO AMBARI-12698");
+    /*
+    List<Grouping> list = new ArrayList<Grouping>();
+    for (Grouping g : groups) {
+      list.add(g);
+    }
+    return list;
+    */
+  }
+
   /**
    * Gets the tasks by which services and components should be upgraded.
    * @return a map of service_name -> map(component_name -> process).
@@ -208,15 +285,17 @@ public class UpgradePack {
     if (null == m_process) {
       m_process = new LinkedHashMap<String, Map<String, ProcessingComponent>>();
 
-      for (ProcessingService svc : processing) {
-        if (!m_process.containsKey(svc.name)) {
-          m_process.put(svc.name, new LinkedHashMap<String, ProcessingComponent>());
-        }
+      if (processing != null) {
+        for (ProcessingService svc : processing) {
+          if (!m_process.containsKey(svc.name)) {
+            m_process.put(svc.name, new LinkedHashMap<String, ProcessingComponent>());
+          }
 
-        Map<String, ProcessingComponent> componentMap = m_process.get(svc.name);
+          Map<String, ProcessingComponent> componentMap = m_process.get(svc.name);
 
-        for (ProcessingComponent pc : svc.components) {
-          componentMap.put(pc.name, pc);
+          for (ProcessingComponent pc : svc.components) {
+            componentMap.put(pc.name, pc);
+          }
         }
       }
     }
@@ -248,8 +327,6 @@ public class UpgradePack {
     public List<ProcessingComponent> components;
   }
 
-
-
   /**
    * A component definition in the 'processing/service' path.
    */
@@ -279,4 +356,14 @@ public class UpgradePack {
     @XmlElement(name="task")
     public List<Task> postDowngradeTasks;
   }
+
+  /**
+   * An intermediate stack definition in
+   * upgrade/upgrade-path/intermediate-stack path
+   */
+  public static class IntermediateStack {
+
+    @XmlAttribute
+    public String version;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/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 eff1b13..ba44408 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 @@ import com.google.gson.JsonPrimitive;
 public class ClusterGrouping extends Grouping {
 
   /**
-   * Stages against a Service and Component, or the Server
+   * Stages against a Service and Component, or the Server, that doesn't need a Processing Component.
    */
   @XmlElement(name="execute-stage")
   public List<ExecuteStage> executionStages;
@@ -166,6 +166,12 @@ public class ClusterGrouping extends Grouping {
     }
   }
 
+  /**
+   * Return a Stage Wrapper for a manual task that runs on the server.
+   * @param ctx Upgrade Context
+   * @param execution Execution Stage
+   * @return Returns a Stage Wrapper
+   */
   private StageWrapper getManualStageWrapper(UpgradeContext ctx, ExecuteStage execution) {
 
     String service   = execution.service;
@@ -204,6 +210,12 @@ public class ClusterGrouping extends Grouping {
         new TaskWrapper(service, component, realHosts, task));
   }
 
+  /**
+   * Return a Stage Wrapper for a task meant to execute code, typically on Ambari Server.
+   * @param ctx Upgrade Context
+   * @param execution Execution Stage
+   * @return Returns a Stage Wrapper, or null if a valid one could not be created.
+   */
   private StageWrapper getExecuteStageWrapper(UpgradeContext ctx, ExecuteStage execution) {
     String service   = execution.service;
     String component = execution.component;
@@ -251,15 +263,18 @@ public class ClusterGrouping extends Grouping {
       return new StageWrapper(
           StageWrapper.Type.RU_TASKS, execution.title,
           new TaskWrapper(service, component, hostNames, et));
-
     }
     return null;
   }
 
-  private void fillHostDetails(ManualTask mt, Map<String, List<String>> unhealthy) {
-
+  /**
+   * Populates the manual task, mt, with information about the list of hosts.
+   * @param mt Manual Task
+   * @param hostToComponents Map from host name to list of components
+   */
+  private void fillHostDetails(ManualTask mt, Map<String, List<String>> hostToComponents) {
     JsonArray arr = new JsonArray();
-    for (Entry<String, List<String>> entry : unhealthy.entrySet()) {
+    for (Entry<String, List<String>> entry : hostToComponents.entrySet()) {
       JsonObject hostObj = new JsonObject();
       hostObj.addProperty("host", entry.getKey());
 
@@ -276,7 +291,5 @@ public class ClusterGrouping extends Grouping {
     obj.add("unhealthy", arr);
 
     mt.structuredOut = obj.toString();
-
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java
new file mode 100644
index 0000000..780f96d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java
@@ -0,0 +1,420 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+
+import com.google.gson.Gson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The {@link ConfigUpgradeChangeDefinition} represents a configuration change. This change can be
+ * defined with conditional statements that will only set values if a condition
+ * passes:
+ * <p/>
+ *
+ * <pre>
+ * {@code
+ * <definition>
+ *   <condition type="hive-site" key="hive.server2.transport.mode" value="binary">
+ *     <type>hive-site</type>
+ *     <key>hive.server2.thrift.port</key>
+ *     <value>10010</value>
+ *   </condition>
+ *   <condition type="hive-site" key="hive.server2.transport.mode" value="http">
+ *     <type>hive-site</type>
+ *     <key>hive.server2.http.port</key>
+ *     <value>10011</value>
+ *   </condition>
+ * </definition>
+ * }
+ * </pre>
+ *
+ * It's also possible to simple set values directly without a precondition
+ * check.
+ *
+ * <pre>
+ * {@code
+ * <definition xsi:type="configure">
+ *   <type>hive-site</type>
+ *   <set key="hive.server2.thrift.port" value="10010"/>
+ *   <set key="foo" value="bar"/>
+ *   <set key="foobar" value="baz"/>
+ * </definition>
+ * }
+ * </pre>
+ *
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ConfigUpgradeChangeDefinition {
+
+  private static Logger LOG = LoggerFactory.getLogger(ConfigUpgradeChangeDefinition.class);
+
+  /**
+   * The key that represents the configuration type to change (ie hdfs-site).
+   */
+  public static final String PARAMETER_CONFIG_TYPE = "configure-task-config-type";
+
+  /**
+   * Setting key/value pairs can be several per task, so they're passed in as a
+   * json-ified list of objects.
+   */
+  public static final String PARAMETER_KEY_VALUE_PAIRS = "configure-task-key-value-pairs";
+
+  /**
+   * Transfers can be several per task, so they're passed in as a json-ified
+   * list of objects.
+   */
+  public static final String PARAMETER_TRANSFERS = "configure-task-transfers";
+
+  /**
+   * Replacements can be several per task, so they're passed in as a json-ified list of
+   * objects.
+   */
+  public static final String PARAMETER_REPLACEMENTS = "configure-task-replacements";
+
+  public static final String actionVerb = "Configuring";
+
+  public static final Float DEFAULT_PRIORITY = 1.0f;
+
+  /**
+   * Gson
+   */
+  private Gson m_gson = new Gson();
+
+  /**
+   * An optional brief description of config changes.
+   */
+  @XmlAttribute(name = "summary")
+  public String summary;
+
+  @XmlAttribute(name = "id", required = true)
+  public String id;
+
+  @XmlElement(name="type")
+  private String configType;
+
+  @XmlElement(name = "set")
+  private List<ConfigurationKeyValue> keyValuePairs;
+
+  @XmlElement(name = "condition")
+  private List<Condition> conditions;
+
+  @XmlElement(name = "transfer")
+  private List<Transfer> transfers;
+
+  @XmlElement(name="replace")
+  private List<Replace> replacements;
+
+  /**
+   * @return the config type
+   */
+  public String getConfigType() {
+    return configType;
+  }
+
+  /**
+   * @return the list of <set key=foo value=bar/> items
+   */
+  public List<ConfigurationKeyValue> getKeyValuePairs() {
+    return keyValuePairs;
+  }
+
+  /**
+   * @return the list of conditions
+   */
+  public List<Condition> getConditions() {
+    return conditions;
+  }
+
+  /**
+   * @return the list of transfers, checking for appropriate null fields.
+   */
+  public List<Transfer> getTransfers() {
+    if (null == transfers) {
+      return Collections.emptyList();
+    }
+
+    List<Transfer> list = new ArrayList<>();
+    for (Transfer t : transfers) {
+      switch (t.operation) {
+        case COPY:
+        case MOVE:
+          if (null != t.fromKey && null != t.toKey) {
+            list.add(t);
+          } else {
+            LOG.warn(String.format("Transfer %s is invalid", t));
+          }
+          break;
+        case DELETE:
+          if (null != t.deleteKey) {
+            list.add(t);
+          } else {
+            LOG.warn(String.format("Transfer %s is invalid", t));
+          }
+
+          break;
+      }
+    }
+
+    return list;
+  }
+
+  /**
+   * @return the replacement tokens, never {@code null}
+   */
+  public List<Replace> getReplacements() {
+    if (null == replacements) {
+      return Collections.emptyList();
+    }
+
+    List<Replace> list = new ArrayList<>();
+    for (Replace r : replacements) {
+      if (null == r.key || null == r.find || null == r.replaceWith) {
+        LOG.warn(String.format("Replacement %s is invalid", r));
+        continue;
+      }
+      list.add(r);
+    }
+
+    return list;
+  }
+
+  /**
+   * Used for configuration updates that should mask their values from being
+   * printed in plain text.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class Masked {
+    @XmlAttribute(name = "mask")
+    public boolean mask = false;
+  }
+
+
+  /**
+   * A key/value pair to set in the type specified by {@link ConfigUpgradeChangeDefinition#configType}
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  @XmlType(name = "set")
+  public static class ConfigurationKeyValue extends Masked {
+    @XmlAttribute(name = "key")
+    public String key;
+
+    @XmlAttribute(name = "value")
+    public String value;
+  }
+
+  /**
+   * A conditional element that will only perform the configuration if the
+   * condition is met.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  @XmlType(name = "condition")
+  public static class Condition {
+    @XmlAttribute(name = "type")
+    private String conditionConfigType;
+
+    @XmlAttribute(name = "key")
+    private String conditionKey;
+
+    @XmlAttribute(name = "value")
+    private String conditionValue;
+
+    @XmlElement(name = "type")
+    private String configType;
+
+    @XmlElement(name = "key")
+    private String key;
+
+    @XmlElement(name = "value")
+    private String value;
+
+    public String getConditionConfigType() {
+      return conditionConfigType;
+    }
+
+    public String getConditionKey() {
+      return conditionKey;
+    }
+
+    public String getConditionValue() {
+      return conditionValue;
+    }
+
+    public String getConfigType() {
+      return configType;
+    }
+
+    public String getKey() {
+      return key;
+    }
+
+    public String getValue() {
+      return value;
+    }
+  }
+
+  /**
+   * A {@code transfer} element will copy, move, or delete the value of one type/key to another type/key.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  @XmlType(name = "transfer")
+  public static class Transfer extends Masked {
+    /**
+     * The type of operation, such as COPY or DELETE.
+     */
+    @XmlAttribute(name = "operation")
+    public TransferOperation operation;
+
+    /**
+     * The configuration type to copy or move from.
+     */
+    @XmlAttribute(name = "from-type")
+    public String fromType;
+
+    /**
+     * The key to copy or move the configuration from.
+     */
+    @XmlAttribute(name = "from-key")
+    public String fromKey;
+
+    /**
+     * The key to copy the configuration value to.
+     */
+    @XmlAttribute(name = "to-key")
+    public String toKey;
+
+    /**
+     * The configuration key to delete, or "*" for all.
+     */
+    @XmlAttribute(name = "delete-key")
+    public String deleteKey;
+
+    /**
+     * If {@code true}, this will ensure that any changed properties are not
+     * removed during a {@link TransferOperation#DELETE}.
+     */
+    @XmlAttribute(name = "preserve-edits")
+    public boolean preserveEdits = false;
+
+    /**
+     * A default value to use when the configurations don't contain the
+     * {@link #fromKey}.
+     */
+    @XmlAttribute(name = "default-value")
+    public String defaultValue;
+
+    /**
+     * A data type to convert the configuration value to when the action is
+     * {@link TransferOperation#COPY}.
+     */
+    @XmlAttribute(name = "coerce-to")
+    public TransferCoercionType coerceTo;
+
+    // if the condition is true apply the transfer action
+    // only supported conditional action is DELETE
+    // if-type/if-key == if-value
+    /**
+     * The key to read for the if condition.
+     */
+    @XmlAttribute(name = "if-key")
+    public String ifKey;
+
+    /**
+     * The config type to read for the if condition.
+     */
+    @XmlAttribute(name = "if-type")
+    public String ifType;
+
+    /**
+     * The property value to compare against for the if condition.
+     */
+    @XmlAttribute(name = "if-value")
+    public String ifValue;
+
+    /**
+     * The keys to keep when the action is {@link TransferOperation#DELETE}.
+     */
+    @XmlElement(name = "keep-key")
+    public List<String> keepKeys = new ArrayList<String>();
+
+    @Override
+    public String toString() {
+      return "Transfer{" +
+              "operation=" + operation +
+              ", fromType='" + fromType + '\'' +
+              ", fromKey='" + fromKey + '\'' +
+              ", toKey='" + toKey + '\'' +
+              ", deleteKey='" + deleteKey + '\'' +
+              ", preserveEdits=" + preserveEdits +
+              ", defaultValue='" + defaultValue + '\'' +
+              ", coerceTo=" + coerceTo +
+              ", ifKey='" + ifKey + '\'' +
+              ", ifType='" + ifType + '\'' +
+              ", ifValue='" + ifValue + '\'' +
+              ", keepKeys=" + keepKeys +
+              '}';
+    }
+  }
+
+  /**
+   * Used to replace strings in a key with other strings.  More complex
+   * scenarios will be possible with regex (when needed)
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  @XmlType(name = "replace")
+  public static class Replace extends Masked {
+    /**
+     * The key name
+     */
+    @XmlAttribute(name="key")
+    public String key;
+
+    /**
+     * The string to find
+     */
+    @XmlAttribute(name="find")
+    public String find;
+
+    /**
+     * The string to replace
+     */
+    @XmlAttribute(name="replace-with")
+    public String replaceWith;
+
+    @Override
+    public String toString() {
+      return "Replace{" +
+              "key='" + key + '\'' +
+              ", find='" + find + '\'' +
+              ", replaceWith='" + replaceWith + '\'' +
+              '}';
+    }
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java
index 8a9e2e5..1164335 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java
@@ -18,7 +18,6 @@
 package org.apache.ambari.server.state.stack.upgrade;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -26,11 +25,10 @@ import java.util.Map;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ambari.server.serveraction.upgrades.ConfigureAction;
 import org.apache.ambari.server.state.Cluster;
@@ -40,41 +38,21 @@ import org.apache.ambari.server.state.DesiredConfig;
 import com.google.gson.Gson;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import static org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer;
+import static org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace;
+import static org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Condition;
+import static org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue;
 
 /**
- * The {@link ConfigureTask} represents a configuration change. This task can be
- * defined with conditional statements that will only set values if a condition
- * passes:
+ * The {@link ConfigureTask} represents a configuration change. This task
+ * contains id of change. Change definitions are located in a separate file (config
+ * upgrade pack). IDs of change definitions share the same namespace within all
+ * stacks
  * <p/>
  *
  * <pre>
  * {@code
- * <task xsi:type="configure">
- *   <condition type="hive-site" key="hive.server2.transport.mode" value="binary">
- *     <type>hive-site</type>
- *     <key>hive.server2.thrift.port</key>
- *     <value>10010</value>
- *   </condition>
- *   <condition type="hive-site" key="hive.server2.transport.mode" value="http">
- *     <type>hive-site</type>
- *     <key>hive.server2.http.port</key>
- *     <value>10011</value>
- *   </condition>
- * </task>
- * }
- * </pre>
- *
- * It's also possible to simple set values directly without a precondition
- * check.
- *
- * <pre>
- * {@code
- * <task xsi:type="configure">
- *   <type>hive-site</type>
- *   <set key="hive.server2.thrift.port" value="10010"/>
- *   <set key="foo" value="bar"/>
- *   <set key="foobar" value="baz"/>
- * </task>
+ * <task xsi:type="configure" id="hdp_2_3_0_0-UpdateHiveConfig"/>
  * }
  * </pre>
  *
@@ -109,6 +87,8 @@ public class ConfigureTask extends ServerSideActionTask {
    */
   public static final String PARAMETER_REPLACEMENTS = "configure-task-replacements";
 
+  public static final String actionVerb = "Configuring";
+  
   /**
    * Gson
    */
@@ -116,29 +96,15 @@ public class ConfigureTask extends ServerSideActionTask {
 
   /**
    * Constructor.
-   *
    */
   public ConfigureTask() {
     implClass = ConfigureAction.class.getName();
   }
 
-  @XmlTransient
   private Task.Type type = Task.Type.CONFIGURE;
 
-  @XmlElement(name="type")
-  private String configType;
-
-  @XmlElement(name = "set")
-  private List<ConfigurationKeyValue> keyValuePairs;
-
-  @XmlElement(name = "condition")
-  private List<Condition> conditions;
-
-  @XmlElement(name = "transfer")
-  private List<Transfer> transfers;
-
-  @XmlElement(name="replace")
-  private List<Replace> replacements;
+  @XmlAttribute(name = "id")
+  public String id;
 
   /**
    * {@inheritDoc}
@@ -148,220 +114,23 @@ public class ConfigureTask extends ServerSideActionTask {
     return type;
   }
 
-  /**
-   * @return the config type
-   */
-  public String getConfigType() {
-    return configType;
-  }
-
-  /**
-   * Used for configuration updates that should mask their values from being
-   * printed in plain text.
-   */
-  @XmlAccessorType(XmlAccessType.FIELD)
-  public static class Masked {
-    @XmlAttribute(name = "mask")
-    public boolean mask = false;
-  }
-
-
-  /**
-   * A key/value pair to set in the type specified by {@link ConfigureTask#type}
-   */
-  @XmlAccessorType(XmlAccessType.FIELD)
-  @XmlType(name = "set")
-  public static class ConfigurationKeyValue extends Masked {
-    @XmlAttribute(name = "key")
-    public String key;
-
-    @XmlAttribute(name = "value")
-    public String value;
-  }
-
-  /**
-   * A conditional element that will only perform the configuration if the
-   * condition is met.
-   */
-  @XmlAccessorType(XmlAccessType.FIELD)
-  @XmlType(name = "condition")
-  public static class Condition {
-    @XmlAttribute(name = "type")
-    private String conditionConfigType;
-
-    @XmlAttribute(name = "key")
-    private String conditionKey;
-
-    @XmlAttribute(name = "value")
-    private String conditionValue;
-
-    @XmlElement(name = "type")
-    private String configType;
-
-    @XmlElement(name = "key")
-    private String key;
-
-    @XmlElement(name = "value")
-    private String value;
-  }
-
-  /**
-   * A {@code transfer} element will copy, move, or delete the value of one type/key to another type/key.
-   */
-  @XmlAccessorType(XmlAccessType.FIELD)
-  @XmlType(name = "transfer")
-  public static class Transfer extends Masked {
-    /**
-     * The type of operation, such as COPY or DELETE.
-     */
-    @XmlAttribute(name = "operation")
-    public TransferOperation operation;
-
-    /**
-     * The configuration type to copy or move from.
-     */
-    @XmlAttribute(name = "from-type")
-    public String fromType;
-
-    /**
-     * The key to copy or move the configuration from.
-     */
-    @XmlAttribute(name = "from-key")
-    public String fromKey;
-
-    /**
-     * The key to copy the configuration value to.
-     */
-    @XmlAttribute(name = "to-key")
-    public String toKey;
-
-    /**
-     * The configuration key to delete, or "*" for all.
-     */
-    @XmlAttribute(name = "delete-key")
-    public String deleteKey;
-
-    /**
-     * If {@code true}, this will ensure that any changed properties are not
-     * removed during a {@link TransferOperation#DELETE}.
-     */
-    @XmlAttribute(name = "preserve-edits")
-    public boolean preserveEdits = false;
-
-    /**
-     * A default value to use when the configurations don't contain the
-     * {@link #fromKey}.
-     */
-    @XmlAttribute(name = "default-value")
-    public String defaultValue;
-
-    /**
-     * A data type to convert the configuration value to when the action is
-     * {@link TransferOperation#COPY}.
-     */
-    @XmlAttribute(name = "coerce-to")
-    public TransferCoercionType coerceTo;
-
-    // if the condition is true apply the transfer action
-    // only supported conditional action is DELETE
-    // if-type/if-key == if-value
-    /**
-     * The key to read for the if condition.
-     */
-    @XmlAttribute(name = "if-key")
-    public String ifKey;
-
-    /**
-     * The config type to read for the if condition.
-     */
-    @XmlAttribute(name = "if-type")
-    public String ifType;
-
-    /**
-     * The property value to compare against for the if condition.
-     */
-    @XmlAttribute(name = "if-value")
-    public String ifValue;
-
-    /**
-     * The keys to keep when the action is {@link TransferOperation#DELETE}.
-     */
-    @XmlElement(name = "keep-key")
-    public List<String> keepKeys = new ArrayList<String>();
-  }
-
-  /**
-   * @return the list of transfers, checking for appropriate null fields.
-   */
-  public List<Transfer> getTransfers() {
-    if (null == transfers) {
-      return Collections.<Transfer>emptyList();
-    }
-
-    List<Transfer> list = new ArrayList<Transfer>();
-    for (Transfer t : transfers) {
-      switch (t.operation) {
-        case COPY:
-        case MOVE:
-          if (null != t.fromKey && null != t.toKey) {
-            list.add(t);
-          }
-          break;
-        case DELETE:
-          if (null != t.deleteKey) {
-            list.add(t);
-          }
-
-          break;
-      }
-    }
-
-    return list;
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.SERVER_SIDE_ACTION;
   }
 
-  /**
-   * Used to replace strings in a key with other strings.  More complex
-   * scenarios will be possible with regex (when needed)
-   */
-  @XmlAccessorType(XmlAccessType.FIELD)
-  @XmlType(name = "replace")
-  public static class Replace extends Masked {
-    /**
-     * The key name
-     */
-    @XmlAttribute(name="key")
-    public String key;
-
-    /**
-     * The string to find
-     */
-    @XmlAttribute(name="find")
-    public String find;
-
-    /**
-     * The string to replace
-     */
-    @XmlAttribute(name="replace-with")
-    public String replaceWith;
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
   }
 
   /**
-   * @return the replacement tokens, never {@code null}
+   * This getter is intended to be used only from tests. In production,
+   * getConfigurationChanges() logic should be used instead
+   * @return id of config upgrade change definition as defined in upgrade pack
    */
-  public List<Replace> getReplacements() {
-    if (null == replacements) {
-      return Collections.emptyList();
-    }
-
-    List<Replace> list = new ArrayList<Replace>();
-    for (Replace r : replacements) {
-      if (null == r.key || null == r.find || null == r.replaceWith) {
-        continue;
-      }
-      list.add(r);
-    }
-
-    return list;
+  public String getId() {
+    return id;
   }
 
   /**
@@ -385,21 +154,41 @@ public class ConfigureTask extends ServerSideActionTask {
    *         handle a configuration task that is unable to set any configuration
    *         values.
    */
-  public Map<String, String> getConfigurationChanges(Cluster cluster) {
-    Map<String, String> configParameters = new HashMap<String, String>();
+  public Map<String, String> getConfigurationChanges(Cluster cluster,
+                                                     ConfigUpgradePack configUpgradePack) {
+    Map<String, String> configParameters = new HashMap<>();
+
+    if (this.id == null || this.id.isEmpty()) {
+      LOG.warn("Config task id is not defined, skipping config change");
+      return configParameters;
+    }
+
+    if (configUpgradePack == null) {
+      LOG.warn("Config upgrade pack is not defined, skipping config change");
+      return configParameters;
+    }
+
+    // extract config change definition, referenced by current ConfigureTask
+    ConfigUpgradeChangeDefinition definition = configUpgradePack.enumerateConfigChangesByID().get(this.id);
+    if (definition == null) {
+      LOG.warn(String.format("Can not resolve config change definition by id %s, " +
+              "skipping config change", this.id));
+      return configParameters;
+    }
 
     // the first matched condition will win; conditions make configuration tasks singular in
     // the properties that can be set - when there is a condition the task will only contain
     // conditions
+    List<Condition> conditions = definition.getConditions();
     if( null != conditions && !conditions.isEmpty() ){
       for (Condition condition : conditions) {
-        String conditionConfigType = condition.conditionConfigType;
-        String conditionKey = condition.conditionKey;
-        String conditionValue = condition.conditionValue;
+        String conditionConfigType = condition.getConditionConfigType();
+        String conditionKey = condition.getConditionKey();
+        String conditionValue = condition.getConditionValue();
 
         // always add the condition's target type just so that we have one to
         // return even if none of the conditions match
-        configParameters.put(PARAMETER_CONFIG_TYPE, condition.configType);
+        configParameters.put(PARAMETER_CONFIG_TYPE, condition.getConfigType());
 
         // check the condition; if it passes, set the configuration properties
         // and break
@@ -407,10 +196,10 @@ public class ConfigureTask extends ServerSideActionTask {
             conditionConfigType, conditionKey);
 
         if (conditionValue.equals(checkValue)) {
-          List<ConfigurationKeyValue> configurations = new ArrayList<ConfigurationKeyValue>(1);
+          List<ConfigurationKeyValue> configurations = new ArrayList<>(1);
           ConfigurationKeyValue keyValue = new ConfigurationKeyValue();
-          keyValue.key = condition.key;
-          keyValue.value = condition.value;
+          keyValue.key = condition.getKey();
+          keyValue.value = condition.getValue();
           configurations.add(keyValue);
 
           configParameters.put(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS,
@@ -422,20 +211,21 @@ public class ConfigureTask extends ServerSideActionTask {
     }
 
     // this task is not a condition task, so process the other elements normally
-    if (null != configType) {
-      configParameters.put(PARAMETER_CONFIG_TYPE, configType);
+    if (null != definition.getConfigType()) {
+      configParameters.put(PARAMETER_CONFIG_TYPE, definition.getConfigType());
     }
 
     // for every <set key=foo value=bar/> add it to this list
-    if (null != keyValuePairs && !keyValuePairs.isEmpty()) {
+    if (null != definition.getKeyValuePairs() && !definition.getKeyValuePairs().isEmpty()) {
       configParameters.put(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS,
-          m_gson.toJson(keyValuePairs));
+          m_gson.toJson(definition.getKeyValuePairs()));
     }
 
     // transfers
+    List<Transfer> transfers = definition.getTransfers();
     if (null != transfers && !transfers.isEmpty()) {
 
-      List<Transfer> allowedTransfers = new ArrayList<Transfer>();
+      List<Transfer> allowedTransfers = new ArrayList<>();
       for (Transfer transfer : transfers) {
         if (transfer.operation == TransferOperation.DELETE) {
           if (StringUtils.isNotBlank(transfer.ifKey) &&
@@ -450,7 +240,7 @@ public class ConfigureTask extends ServerSideActionTask {
             if (!ifValue.toLowerCase().equals(StringUtils.lowerCase(checkValue))) {
               // skip adding
               LOG.info("Skipping property delete for {}/{} as the value {} for {}/{} is not equal to {}",
-                       this.getConfigType(), transfer.deleteKey, checkValue, ifConfigType, ifKey, ifValue);
+                       definition.getConfigType(), transfer.deleteKey, checkValue, ifConfigType, ifKey, ifValue);
               continue;
             }
           }
@@ -461,6 +251,7 @@ public class ConfigureTask extends ServerSideActionTask {
     }
 
     // replacements
+    List<Replace> replacements = definition.getReplacements();
     if( null != replacements && !replacements.isEmpty() ){
       configParameters.put(ConfigureTask.PARAMETER_REPLACEMENTS, m_gson.toJson(replacements));
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ExecuteTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ExecuteTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ExecuteTask.java
index a0afdfb..d175a13 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ExecuteTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ExecuteTask.java
@@ -66,8 +66,20 @@ public class ExecuteTask extends Task {
   @XmlElement(name="command")
   public String command;
 
+  public static final String actionVerb = "Executing";
+
   @Override
   public Task.Type getType() {
     return type;
   }
+
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.RU_TASKS;
+  }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/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 cd27722..8f23803 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Grouping.java
@@ -36,7 +36,7 @@ import org.apache.commons.lang.StringUtils;
 /**
  *
  */
-@XmlSeeAlso(value = { ColocatedGrouping.class, ClusterGrouping.class, ServiceCheckGrouping.class })
+@XmlSeeAlso(value = { ColocatedGrouping.class, ClusterGrouping.class, UpdateStackGrouping.class, ServiceCheckGrouping.class, RestartGrouping.class, StartGrouping.class, StopGrouping.class })
 public class Grouping {
 
   @XmlAttribute(name="name")
@@ -60,7 +60,6 @@ public class Grouping {
   @XmlElement(name="direction")
   public Direction intendedDirection = null;
 
-
   /**
    * Gets the default builder.
    */
@@ -68,11 +67,11 @@ public class Grouping {
     return new DefaultBuilder(this, performServiceCheck);
   }
 
-
   private static class DefaultBuilder extends StageWrapperBuilder {
 
     private List<StageWrapper> m_stages = new ArrayList<StageWrapper>();
     private Set<String> m_servicesToCheck = new HashSet<String>();
+
     private boolean m_serviceCheck = true;
 
     private DefaultBuilder(Grouping grouping, boolean serviceCheck) {
@@ -85,14 +84,14 @@ public class Grouping {
      * E.g., preupgrade, restart hosts(0), ..., restart hosts(n-1), postupgrade
      * @param hostsType the order collection of hosts, which may have a master and secondary
      * @param service the service name
-     * @param pc the ProcessingComponent derived from the upgrade pack.
+     * @param pc the AffectedComponent derived from the upgrade pack.
      */
     @Override
     public void add(UpgradeContext ctx, HostsType hostsType, String service,
        boolean clientOnly, ProcessingComponent pc) {
-
       boolean forUpgrade = ctx.getDirection().isUpgrade();
 
+      // Construct the pre tasks during Upgrade/Downgrade direction.
       List<TaskBucket> buckets = buckets(resolveTasks(forUpgrade, true, pc));
       for (TaskBucket bucket : buckets) {
         List<TaskWrapper> preTasks = TaskWrapperBuilder.getTaskList(service, pc.name, hostsType, bucket.tasks);
@@ -108,19 +107,20 @@ public class Grouping {
       }
 
       // !!! FIXME upgrade definition have only one step, and it better be a restart
+      // Add the processing component
       if (null != pc.tasks && 1 == pc.tasks.size()) {
         Task t = pc.tasks.get(0);
-        if (RestartTask.class.isInstance(t)) {
-          for (String hostName : hostsType.hosts) {
-            StageWrapper stage = new StageWrapper(
-                StageWrapper.Type.RESTART,
-                getStageText("Restarting", ctx.getComponentDisplay(service, pc.name), Collections.singleton(hostName)),
-                new TaskWrapper(service, pc.name, Collections.singleton(hostName), t));
-            m_stages.add(stage);
-          }
+
+        for (String hostName : hostsType.hosts) {
+          StageWrapper stage = new StageWrapper(
+              t.getStageWrapperType(),
+              getStageText(t.getActionVerb(), ctx.getComponentDisplay(service, pc.name), Collections.singleton(hostName)),
+              new TaskWrapper(service, pc.name, Collections.singleton(hostName), t));
+          m_stages.add(stage);
         }
       }
 
+      // Construct the post tasks during Upgrade/Downgrade direction.
       buckets = buckets(resolveTasks(forUpgrade, false, pc));
       for (TaskBucket bucket : buckets) {
         List<TaskWrapper> postTasks = TaskWrapperBuilder.getTaskList(service, pc.name, hostsType, bucket.tasks);
@@ -135,7 +135,8 @@ public class Grouping {
         }
       }
 
-      if (!clientOnly) {
+      // Potentially add a service check
+      if (this.m_serviceCheck && !clientOnly) {
         m_servicesToCheck.add(service);
       }
     }
@@ -163,7 +164,6 @@ public class Grouping {
 
       if (upgradeContext.getDirection().isUpgrade() && m_serviceCheck
           && m_servicesToCheck.size() > 0) {
-
         StageWrapper wrapper = new StageWrapper(StageWrapper.Type.SERVICE_CHECK,
             "Service Check " + StringUtils.join(displays, ", "), tasks.toArray(new TaskWrapper[0]));
 
@@ -202,12 +202,14 @@ public class Grouping {
     }
 
     return holders;
-
   }
 
   private static class TaskBucket {
+
     private StageWrapper.Type type;
+
     private List<Task> tasks = new ArrayList<Task>();
+
     private TaskBucket(Task initial) {
       switch (initial.getType()) {
         case CONFIGURE:
@@ -221,6 +223,12 @@ public class Grouping {
         case RESTART:
           type = StageWrapper.Type.RESTART;
           break;
+        case START:
+          type = StageWrapper.Type.START;
+          break;
+        case STOP:
+          type = StageWrapper.Type.STOP;
+          break;
         case SERVICE_CHECK:
           type = StageWrapper.Type.SERVICE_CHECK;
           break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ManualTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ManualTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ManualTask.java
index 2b1ba56..a0a347a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ManualTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ManualTask.java
@@ -52,4 +52,8 @@ public class ManualTask extends ServerSideActionTask {
     return type;
   }
 
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.SERVER_SIDE_ACTION;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
index 2e17cf4..6a36522 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
@@ -22,7 +22,6 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.regex.Pattern;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -159,47 +158,29 @@ public class RepositoryVersionHelper {
    * @param stackName stack name
    * @param stackVersion stack version
    * @param repositoryVersion target repository version
+   * @param upgradeType if not {@code null} null, will only return upgrade packs whose type matches.
    * @return upgrade pack name
    * @throws AmbariException if no upgrade packs suit the requirements
    */
-  public String getUpgradePackageName(String stackName, String stackVersion, String repositoryVersion) throws AmbariException {
+  public String getUpgradePackageName(String stackName, String stackVersion, String repositoryVersion, UpgradeType upgradeType) throws AmbariException {
     final Map<String, UpgradePack> upgradePacks = ambariMetaInfo.getUpgradePacks(stackName, stackVersion);
-    for (Entry<String, UpgradePack> upgradePackEntry : upgradePacks.entrySet()) {
-      final UpgradePack upgradePack = upgradePackEntry.getValue();
-      final String upgradePackName = upgradePackEntry.getKey();
+    for (UpgradePack upgradePack : upgradePacks.values()) {
+      final String upgradePackName = upgradePack.getName();
+
+      if (null != upgradeType && upgradePack.getType() != upgradeType) {
+        continue;
+      }
+
       // check that upgrade pack has <target> node
       if (StringUtils.isBlank(upgradePack.getTarget())) {
         LOG.error("Upgrade pack " + upgradePackName + " is corrupted, it should contain <target> node");
         continue;
       }
-
-      // check that upgrade pack can be applied to selected stack
-      // converting 2.2.*.* -> 2\.2(\.\d+)?(\.\d+)?(-\d+)?
-      String regexPattern = upgradePack.getTarget();
-      regexPattern = regexPattern.replaceAll("\\.", "\\\\."); // . -> \.
-      regexPattern = regexPattern.replaceAll("\\\\\\.\\*", "(\\\\\\.\\\\d+)?"); // \.* -> (\.\d+)?
-      regexPattern = regexPattern.concat("(-\\d+)?");
-      if (Pattern.matches(regexPattern, repositoryVersion)) {
+      if (upgradePack.canBeApplied(repositoryVersion)) {
         return upgradePackName;
       }
     }
-    throw new AmbariException("There were no suitable upgrade packs for stack " + stackName + " " + stackVersion);
-  }
-
-  /**
-   * Scans the given stack for upgrade packages which can be applied to update the cluster to given repository version.
-   * Returns NONE if there were no suitable packages.
-   *
-   * @param stackName stack name
-   * @param stackVersion stack version
-   * @param repositoryVersion target repository version
-   * @return upgrade pack name or NONE
-   */
-  public String getUpgradePackageNameSafe(String stackName, String stackVersion, String repositoryVersion) {
-    try {
-      return getUpgradePackageName(stackName, stackVersion, repositoryVersion);
-    } catch (AmbariException ex) {
-      return "NONE";
-    }
+    throw new AmbariException("There were no suitable upgrade packs for stack " + stackName + " " + stackVersion +
+        ((null != upgradeType) ? " and upgrade type " + upgradeType : ""));
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartGrouping.java
new file mode 100644
index 0000000..529cadd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartGrouping.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Used for a group that restarts services.
+ */
+@XmlType(name="restart")
+public class RestartGrouping extends Grouping implements UpgradeFunction {
+
+  private static Logger LOG = LoggerFactory.getLogger(RestartGrouping.class);
+
+  @Override
+  public Task.Type getFunction() {
+    return Task.Type.RESTART;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartTask.java
index 1b69b5b..fac0179 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RestartTask.java
@@ -28,14 +28,26 @@ import javax.xml.bind.annotation.XmlType;
  */
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name="restart")
+@XmlType(name="restart-task")
 public class RestartTask extends Task {
 
   @XmlTransient
   private Task.Type type = Task.Type.RESTART;
 
+  public static final String actionVerb = "Restarting";
+
   @Override
   public Task.Type getType() {
     return type;
   }
+
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.RESTART;
+  }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
index 74144b7..5f6438c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
@@ -39,4 +39,8 @@ public class ServerActionTask extends ServerSideActionTask {
     return type;
   }
 
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.SERVER_SIDE_ACTION;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerSideActionTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerSideActionTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerSideActionTask.java
index 97981ae..595465d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerSideActionTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerSideActionTask.java
@@ -27,7 +27,14 @@ public abstract class ServerSideActionTask extends Task {
   @XmlAttribute(name="class")
   protected String implClass;
 
+  public static final String actionVerb = "Executing";
+
   public String getImplementationClass() {
     return implClass;
   }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/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 6061895..af63656 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
@@ -50,10 +50,17 @@ public class ServiceCheckGrouping extends Grouping {
 
   private static Logger LOG = LoggerFactory.getLogger(ServiceCheckGrouping.class);
 
+  /**
+   * During a Rolling Upgrade, the priority services are ran first, then the remaining services in the cluster.
+   * During a Stop-and-Start Upgrade, only the priority services are ran.
+   */
   @XmlElementWrapper(name="priority")
   @XmlElement(name="service")
   private Set<String> priorityServices = new LinkedHashSet<String>();
 
+  /**
+   * During a Rolling Upgrade, exclude certain services.
+   */
   @XmlElementWrapper(name="exclude")
   @XmlElement(name="service")
   private Set<String> excludeServices = new HashSet<String>();
@@ -132,19 +139,20 @@ public class ServiceCheckGrouping extends Grouping {
         }
       }
 
-      // create stages for everything else, as long it is valid
-      for (String service : clusterServices) {
-        if (excludeServices.contains(service)) {
-          continue;
-        }
-
-        if (checkServiceValidity(upgradeContext, service, serviceMap)) {
-          StageWrapper wrapper = new StageWrapper(
-              StageWrapper.Type.SERVICE_CHECK,
-              "Service Check " + upgradeContext.getServiceDisplay(service),
-              new TaskWrapper(service, "", Collections.<String>emptySet(),
-                  new ServiceCheckTask()));
-          result.add(wrapper);
+      if (upgradeContext.getType() == UpgradeType.ROLLING) {
+        // During Rolling Upgrade, create stages for everything else, as long it is valid
+        for (String service : clusterServices) {
+          if (ServiceCheckGrouping.this.excludeServices.contains(service)) {
+            continue;
+          }
+          if (checkServiceValidity(upgradeContext, service, serviceMap)) {
+            StageWrapper wrapper = new StageWrapper(
+                StageWrapper.Type.SERVICE_CHECK,
+                "Service Check " + upgradeContext.getServiceDisplay(service),
+                new TaskWrapper(service, "", Collections.<String>emptySet(),
+                    new ServiceCheckTask()));
+            result.add(wrapper);
+          }
         }
       }
       return result;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckTask.java
index 5893edf..d6c19b8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckTask.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServiceCheckTask.java
@@ -34,8 +34,20 @@ public class ServiceCheckTask extends Task {
   @XmlTransient
   private Task.Type type = Task.Type.SERVICE_CHECK;
 
+  public static final String actionVerb = "Running";
+
   @Override
   public Task.Type getType() {
     return type;
   }
+
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.SERVICE_CHECK;
+  }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapper.java
index eac5ce5..92df3b5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StageWrapper.java
@@ -92,7 +92,7 @@ public class StageWrapper {
   }
 
   /**
-   * @param text the new text for the stage
+   * @param newText the new text for the stage
    */
   public void setText(String newText) {
     text = newText;
@@ -113,6 +113,8 @@ public class StageWrapper {
     SERVER_SIDE_ACTION,
     RESTART,
     RU_TASKS,
-    SERVICE_CHECK
+    SERVICE_CHECK,
+    STOP,
+    START
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/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 57cd41f..47a28d7 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
@@ -28,7 +28,7 @@ import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 
 /**
- * Defines how to build stages.
+ * Defines how to build stages for an Upgrade or Downgrade.
  */
 public abstract class StageWrapperBuilder {
 
@@ -55,7 +55,7 @@ public abstract class StageWrapperBuilder {
   /**
    * Adds a processing component that will be built into stage wrappers.
    *
-   * @param upgradeContext
+   * @param ctx
    *          the upgrade context
    * @param hostsType
    *          the hosts, along with their type
@@ -64,9 +64,9 @@ public abstract class StageWrapperBuilder {
    * @param clientOnly
    *          whether the service is client only, no service checks
    * @param pc
-   *          the ProcessingComponent derived from the upgrade pack
+   *          the AffectedComponent derived from the upgrade pack
    */
-  public abstract void add(UpgradeContext upgradeContext, HostsType hostsType, String service,
+  public abstract void add(UpgradeContext ctx, HostsType hostsType, String service,
       boolean clientOnly, ProcessingComponent pc);
 
   /**
@@ -182,9 +182,14 @@ public abstract class StageWrapperBuilder {
    * @param forUpgrade  {@code true} if resolving for an upgrade, {@code false} for downgrade
    * @param preTasks    {@code true} if loading pre-upgrade or pre-downgrade
    * @param pc          the processing component holding task definitions
-   * @return
+   * @return A collection, potentially empty, of the tasks to run, which may contain either
+   * pre or post tasks if they exist, and the order depends on whether it's an upgrade or downgrade.
    */
   protected List<Task> resolveTasks(boolean forUpgrade, boolean preTasks, ProcessingComponent pc) {
+    if (null == pc) {
+      return Collections.emptyList();
+    }
+
     if (forUpgrade) {
       return preTasks ? pc.preTasks : pc.postTasks;
     } else {
@@ -193,6 +198,4 @@ public abstract class StageWrapperBuilder {
         (null == pc.postDowngradeTasks ? pc.postTasks : pc.postDowngradeTasks);
     }
   }
-
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartGrouping.java
new file mode 100644
index 0000000..7237599
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartGrouping.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ *  Used for a group that starts services.
+ */
+@XmlType(name="start")
+public class StartGrouping extends Grouping implements UpgradeFunction {
+
+  private static Logger LOG = LoggerFactory.getLogger(StartGrouping.class);
+
+  @Override
+  public Task.Type  getFunction() {
+    return Task.Type.START;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartTask.java
new file mode 100644
index 0000000..4d05dcb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StartTask.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Used to represent a start of a component.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="start-task")
+public class StartTask extends Task {
+
+  @XmlTransient
+  private Type type = Type.START;
+
+  public static final String actionVerb = "Starting";
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.START;
+  }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopGrouping.java
new file mode 100644
index 0000000..5cf1149
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopGrouping.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ *  Used for a group that stops services.
+ */
+@XmlType(name="stop")
+public class StopGrouping extends Grouping implements UpgradeFunction {
+
+  private static Logger LOG = LoggerFactory.getLogger(StopGrouping.class);
+
+  @Override
+  public Task.Type getFunction() {
+    return Task.Type.STOP;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopTask.java
new file mode 100644
index 0000000..30a557f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/StopTask.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Used to represent a stop of a component.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="stop-task")
+public class StopTask extends Task {
+
+  @XmlTransient
+  private Type type = Type.STOP;
+
+  public static final String actionVerb = "Stopping";
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public StageWrapper.Type getStageWrapperType() {
+    return StageWrapper.Type.STOP;
+  }
+
+  @Override
+  public String getActionVerb() {
+    return actionVerb;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
index 6416b57..f443e53 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
@@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlSeeAlso;
 /**
  * Base class to identify the items that could possibly occur during an upgrade
  */
-@XmlSeeAlso(value={ExecuteTask.class, ConfigureTask.class, ManualTask.class, RestartTask.class, ServerActionTask.class})
+@XmlSeeAlso(value={ExecuteTask.class, ConfigureTask.class, ManualTask.class, RestartTask.class, StartTask.class, StopTask.class, ServerActionTask.class})
 public abstract class Task {
 
   /**
@@ -38,6 +38,16 @@ public abstract class Task {
    */
   public abstract Type getType();
 
+  /**
+   * @return when a single Task is constructed, this is the type of stage it should belong to.
+   */
+  public abstract StageWrapper.Type getStageWrapperType();
+
+  /**
+   * @return a verb to display that describes the type of task, e.g., "executing".
+   */
+  public abstract String getActionVerb();
+
   @Override
   public String toString() {
     return getType().toString();
@@ -64,6 +74,14 @@ public abstract class Task {
      */
     RESTART,
     /**
+     * Task that is a start command.
+     */
+    START,
+    /**
+     * Task that is a stop command.
+     */
+    STOP,
+    /**
      * Task that is a service check
      */
     SERVICE_CHECK,
@@ -83,7 +101,7 @@ public abstract class Task {
      * @return {@code true} if the task is a command type (as opposed to an action)
      */
     public boolean isCommand() {
-      return this == RESTART || this == SERVICE_CHECK;
+      return this == RESTART || this == START || this == STOP || this == SERVICE_CHECK;
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
new file mode 100644
index 0000000..9dc9af8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpdateStackGrouping.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Used to represent operations that update the Stack.
+ * This is primarily needed during a {@link UpgradeType#NON_ROLLING} upgrade.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="update-stack")
+public class UpdateStackGrouping extends ClusterGrouping {
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeFunction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeFunction.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeFunction.java
new file mode 100644
index 0000000..d58316d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeFunction.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;
+
+public interface UpgradeFunction {
+
+  /**
+   * @return Return the function that the group must provide.
+   */
+  public Task.Type getFunction();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeType.java
new file mode 100644
index 0000000..3acfb9f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeType.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.stack.upgrade;
+
+import javax.xml.bind.annotation.XmlEnumValue;
+
+/**
+ * Indicates the type of Upgrade performed.
+ */
+public enum UpgradeType {
+  /**
+   * Services are up the entire time
+   */
+  @XmlEnumValue("ROLLING")
+  ROLLING,
+  /**
+   * All services are stopped, then started
+   */
+  @XmlEnumValue("NON_ROLLING")
+  NON_ROLLING;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index 71d0581..c0804ff 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -1577,7 +1577,6 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
         stackEntity,
         version,
         stackId.getStackName() + "-" + version,
-        repositoryVersionHelper.getUpgradePackageNameSafe(stackId.getStackName(), stackId.getStackVersion(), version),
         repositoryVersionHelper.serializeOperatingSystems(stackInfo.getRepositories()));
   }