You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2013/03/02 00:08:02 UTC

svn commit: r1451761 - in /incubator/ambari/trunk: ./ ambari-server/src/main/java/org/apache/ambari/server/ ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ ambari-server/src/main/java/org/apache/ambari/server/agent/ ambari-server/sr...

Author: swagle
Date: Fri Mar  1 23:08:02 2013
New Revision: 1451761

URL: http://svn.apache.org/r1451761
Log:
AMBARI-1528. Upgrade request support at Ambari. (Sumit Mohanty via swagle)

Added:
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostUpgradeEvent.java
    incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/RoleGraphTest.java
Modified:
    incubator/ambari/trunk/CHANGES.txt
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/Role.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/metadata/RoleCommandOrder.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEvent.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/State.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java

Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Fri Mar  1 23:08:02 2013
@@ -12,6 +12,8 @@ Trunk (unreleased changes):
 
  NEW FEATURES
 
+ AMBARI-1528. Upgrade request support at Ambari. (Sumit Mohanty via swagle)
+
  AMBARI-1541. Upgrade task support in agent. (Sumit Mohanty via swagle)
 
  AMBARI-1540. Reassign Master Wizard - Steps 3 and 4 (reconfigure

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/Role.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/Role.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/Role.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/Role.java Fri Mar  1 23:08:02 2013
@@ -36,9 +36,6 @@ public enum Role {
   TASKTRACKER,
   MAPREDUCE_CLIENT,
   JAVA_JCE,
-  KERBEROS_SERVER,
-  KERBEROS_CLIENT,
-  KERBEROS_ADMIN_CLIENT,
   HADOOP_CLIENT,
   JOBTRACKER_SERVICE_CHECK,
   MAPREDUCE_SERVICE_CHECK,
@@ -68,6 +65,6 @@ public enum Role {
   GANGLIA_MONITOR,
   GMOND_SERVICE_CHECK,
   GMETAD_SERVICE_CHECK,
-  MONTOR_WEBSERVER,
+  MONITOR_WEBSERVER,
   DECOMMISSION_DATANODE
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java Fri Mar  1 23:08:02 2013
@@ -23,5 +23,6 @@ public enum RoleCommand {
   START,
   STOP,
   EXECUTE,
-  ABORT
+  ABORT,
+  UPGRADE
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java Fri Mar  1 23:08:02 2013
@@ -143,7 +143,7 @@ class ActionScheduler implements Runnabl
         }
       }
       if (failed) {
-        LOG.warn("Operation completely failed, borting request id:"
+        LOG.warn("Operation completely failed, aborting request id:"
             + s.getRequestId());
         db.abortOperation(s.getRequestId());
         return;

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java Fri Mar  1 23:08:02 2013
@@ -51,6 +51,7 @@ public class ExecutionCommand extends Ag
   private Map<String, List<String>> clusterHostInfo = 
       new HashMap<String, List<String>>();
   private Map<String, Map<String, String>> configurations;
+  private Map<String, String> commandParams;
   private String serviceName;
   
   @JsonProperty("commandId")
@@ -180,6 +181,16 @@ public class ExecutionCommand extends Ag
     this.configurations = configurations;
   }
 
+  @JsonProperty("commandParams")
+  public Map<String, String> getCommandParams() {
+    return commandParams;
+  }
+
+  @JsonProperty("commandParams")
+  public void setCommandParams(Map<String, String> commandParams) {
+    this.commandParams = commandParams;
+  }
+
   @JsonProperty("serviceName")
   public String getServiceName() {
     return serviceName;

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java Fri Mar  1 23:08:02 2013
@@ -109,6 +109,10 @@ public class Configuration {
   public static final String SRVR_HOSTS_MAPPING = 
       "server.hosts.mapping";
 
+  // Command parameter names
+  public static final String UPGRADE_FROM_STACK = "source_stack_version";
+  public static final String UPGRADE_TO_STACK = "target_stack_version";
+
   public static final String SSL_TRUSTSTORE_PATH_KEY = "ssl.trustStore.path";
   public static final String SSL_TRUSTSTORE_PASSWORD_KEY = "ssl.trustStore.password";
   public static final String SSL_TRUSTSTORE_TYPE_KEY = "ssl.trustStore.type";

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java Fri Mar  1 23:08:02 2013
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller;
 
+import java.io.File;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -76,6 +77,7 @@ import org.apache.ambari.server.state.sv
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -95,7 +97,7 @@ public class AmbariManagementControllerI
 
   private final Clusters clusters;
 
-  private String baseLogDir = "/tmp/ambari/";
+  private String baseLogDir = "/tmp/ambari";
 
   private final ActionManager actionManager;
 
@@ -131,7 +133,6 @@ public class AmbariManagementControllerI
   @Inject
   private Configuration configs;
 
-
   
   final private String masterHostname;
 
@@ -909,11 +910,10 @@ public class AmbariManagementControllerI
         }
       }
     }
-
   }
 
   private Stage createNewStage(Cluster cluster, long requestId) {
-    String logDir = baseLogDir + "/" + requestId;
+    String logDir = baseLogDir + File.pathSeparator + requestId;
     Stage stage = new Stage(requestId, logDir, cluster.getClusterName());
     return stage;
   }
@@ -922,7 +922,7 @@ public class AmbariManagementControllerI
       Stage stage, ServiceComponentHost scHost,
       Map<String, Map<String, String>> configurations,
       RoleCommand command,
-      long nowTimestamp,
+      Map<String, String> commandParams,
       ServiceComponentHostEvent event) throws AmbariException {
 
     stage.addHostRoleExecutionCommand(scHost.getHostName(), Role.valueOf(scHost
@@ -940,6 +940,8 @@ public class AmbariManagementControllerI
 
     execCmd.setConfigurations(configurations);
 
+    execCmd.setCommandParams(commandParams);
+
     // send stack info to agent
     StackId stackId = scHost.getDesiredStackVersion();
     Map<String, List<RepositoryInfo>> repos = ambariMetaInfo.getRepository(
@@ -1386,11 +1388,9 @@ public class AmbariManagementControllerI
 
   }
 
-
   @Override
   public synchronized RequestStatusResponse updateCluster(ClusterRequest request)
       throws AmbariException {
-    // for now only update host list supported
     if (request.getClusterName() == null
         || request.getClusterName().isEmpty()) {
       throw new IllegalArgumentException("Invalid arguments, cluster name"
@@ -1403,37 +1403,239 @@ public class AmbariManagementControllerI
           + ", request=" + request);
     }
 
-    final Cluster c = clusters.getCluster(request.getClusterName());
-    if (null != request.getHostNames()) {
-      clusters.mapHostsToCluster(request.getHostNames(),
-          request.getClusterName());
-    }
+    final Cluster cluster = clusters.getCluster(request.getClusterName());
 
-    if (!request.getStackVersion().equals(
-        c.getDesiredStackVersion().getStackId())) {
-      throw new IllegalArgumentException("Update of desired stack version"
-          + " not supported");
-    }
-    
     // set or create configuration mapping (and optionally create the map of properties)
     if (null != request.getDesiredConfig()) {
       ConfigurationRequest cr = request.getDesiredConfig();
-      
+
       if (null != cr.getProperties() && cr.getProperties().size() > 0) {
-        cr.setClusterName(c.getClusterName());
+        cr.setClusterName(cluster.getClusterName());
         createConfiguration(cr);
       }
-      
-      Config baseConfig = c.getConfig(cr.getType(), cr.getVersionTag());
-      if (null != baseConfig)
-        c.addDesiredConfig(baseConfig);
-      
+
+      Config baseConfig = cluster.getConfig(cr.getType(), cr.getVersionTag());
+      if (null != baseConfig) {
+        cluster.addDesiredConfig(baseConfig);
+      }
+    }
+
+    StackId currentVersion = cluster.getCurrentStackVersion();
+    StackId desiredVersion = cluster.getDesiredStackVersion();
+    String requestedVersionString = request.getStackVersion();
+    StackId requestedVersion = null;
+
+    // Set the current version value if its not already set
+    if (currentVersion == null) {
+      cluster.setCurrentStackVersion(desiredVersion);
+      currentVersion = cluster.getCurrentStackVersion();
+    }
+
+    boolean requiresHostListUpdate =
+        request.getHostNames() != null && !request.getHostNames().isEmpty();
+    // TODO Should upgrade be allowed to upgrade all un-upgraded hosts
+    // even if the cluster says its upgraded
+    boolean requiresVersionUpdate = requestedVersionString != null
+        && !requestedVersionString.isEmpty();
+    if (requiresVersionUpdate) {
+      requestedVersion = new StackId(requestedVersionString);
+      if (!requestedVersion.getStackName().equals(currentVersion.getStackName())) {
+        throw new AmbariException("Upgrade not possible between different stacks.");
+      }
+      requiresVersionUpdate = !currentVersion.equals(requestedVersion);
+    }
+
+    if (requiresVersionUpdate && requiresHostListUpdate) {
+      throw new IllegalArgumentException("Invalid arguments, "
+          + "cluster version cannot be upgraded"
+          + " along with host list modifications");
+    }
+
+    if (requiresHostListUpdate) {
+      clusters.mapHostsToCluster(
+          request.getHostNames(), request.getClusterName());
+    }
+
+    if (requiresVersionUpdate) {
+      boolean retry = false;
+      if (0 == currentVersion.compareTo(desiredVersion)) {
+        if (1 != requestedVersion.compareTo(currentVersion)) {
+          throw new AmbariException("Target version : " + requestedVersion
+              + " must be greater than current version : " + currentVersion);
+        } else {
+          StackInfo stackInfo =
+              ambariMetaInfo.getStackInfo(requestedVersion.getStackName(), requestedVersion.getStackVersion());
+          if (stackInfo == null) {
+            throw new AmbariException("Target version : " + requestedVersion
+                + " is not a recognized version");
+          }
+          // TODO Ensure its an allowed upgrade using AmbariMetaInfo
+          //if(!upgradeAllowed(stackInfo, requestedVersion))
+          //{
+          //  throw new AmbariException("Upgrade is not allowed from " + currentVersion
+          //      + " to the target version " + requestedVersion);
+          //}
+        }
+      } else {
+        retry = true;
+        if (0 != requestedVersion.compareTo(desiredVersion)) {
+          throw new AmbariException("Upgrade in progress to target version : "
+              + desiredVersion
+              + ". Illegal request to upgrade to : " + requestedVersion);
+        }
+      }
+
+      boolean activeComponentExists = checkIfActiveComponentsExist(cluster);
+      if (activeComponentExists) {
+        throw new AmbariException("Upgrade needs all services to be stopped.");
+      }
+
+      // TODO Ensure no other upgrade is active
+      /**
+       * There exists no active upgrade. Perform a final check of current stack version
+       * and proceed if upgrade is still required. Upgrade is idempotent so this check
+       * is only to avoid potentially expensive stage creation.
+       */
+      cluster.refresh();
+      if (requestedVersion.equals(cluster.getCurrentStackVersion())) {
+        return null;
+      }
+
+      if (!retry) {
+        cluster.setDesiredStackVersion(requestedVersion);
+        for (Service service : cluster.getServices().values()) {
+          service.setDesiredStackVersion(requestedVersion);
+          for (ServiceComponent component : service.getServiceComponents().values()) {
+            component.setDesiredStackVersion(requestedVersion);
+            for (ServiceComponentHost componentHost : component.getServiceComponentHosts().values()) {
+              componentHost.setDesiredStackVersion(requestedVersion);
+            }
+          }
+        }
+      }
+
+      Map<State, List<Service>> changedServices
+          = new HashMap<State, List<Service>>();
+      Map<State, List<ServiceComponent>> changedComps =
+          new HashMap<State, List<ServiceComponent>>();
+      Map<String, Map<State, List<ServiceComponentHost>>> changedScHosts =
+          new HashMap<String, Map<State, List<ServiceComponentHost>>>();
+
+      fillComponentsToUpgrade(request, cluster, changedServices, changedComps, changedScHosts);
+      Map<String, String> requestParameters = new HashMap<String, String>();
+      requestParameters.put(Configuration.UPGRADE_TO_STACK, gson.toJson(requestedVersion));
+      requestParameters.put(Configuration.UPGRADE_FROM_STACK, gson.toJson(currentVersion));
+
+      return doStageCreation(cluster, changedServices, changedComps, changedScHosts, requestParameters);
     }
-    
 
     return null;
   }
 
+  private void fillComponentsToUpgrade(ClusterRequest request, Cluster cluster,
+           Map<State, List<Service>> changedServices, Map<State, List<ServiceComponent>> changedComps,
+           Map<String, Map<State, List<ServiceComponentHost>>> changedScHosts) throws AmbariException {
+    for (Service service : cluster.getServices().values()) {
+      State oldState = service.getDesiredState();
+      State newState = State.INSTALLED;
+
+      if (!isValidDesiredStateTransition(oldState, newState)) {
+        throw new AmbariException("Invalid transition for"
+            + " service"
+            + ", clusterName=" + cluster.getClusterName()
+            + ", clusterId=" + cluster.getClusterId()
+            + ", serviceName=" + service.getName()
+            + ", currentDesiredState=" + oldState
+            + ", newDesiredState=" + newState);
+      }
+      changedServices.put(newState, new ArrayList<Service>());
+      changedServices.get(newState).add(service);
+
+      for (ServiceComponent sc : service.getServiceComponents().values()) {
+        State oldScState = sc.getDesiredState();
+        if (newState != oldScState) {
+          if (!isValidDesiredStateTransition(oldScState, newState)) {
+            throw new AmbariException("Invalid transition for"
+                + " servicecomponent"
+                + ", clusterName=" + cluster.getClusterName()
+                + ", clusterId=" + cluster.getClusterId()
+                + ", serviceName=" + sc.getServiceName()
+                + ", componentName=" + sc.getName()
+                + ", currentDesiredState=" + oldScState
+                + ", newDesiredState=" + newState);
+          }
+          changedComps.put(newState, new ArrayList<ServiceComponent>());
+          changedComps.get(newState).add(sc);
+        }
+        LOG.info("Handling upgrade to ServiceComponent"
+            + ", clusterName=" + request.getClusterName()
+            + ", serviceName=" + service.getName()
+            + ", componentName=" + sc.getName()
+            + ", currentDesiredState=" + oldScState
+            + ", newDesiredState=" + newState);
+
+        for (ServiceComponentHost sch : sc.getServiceComponentHosts().values()) {
+          State currSchState = sch.getState();
+          if (sch.getStackVersion().equals(sch.getDesiredStackVersion())
+              && newState == currSchState) {
+            LOG.info("Ignoring ServiceComponentHost"
+                + ", clusterName=" + request.getClusterName()
+                + ", serviceName=" + service.getName()
+                + ", componentName=" + sc.getName()
+                + ", hostname=" + sch.getHostName()
+                + ", currentState=" + currSchState
+                + ", newDesiredState=" + newState
+                + ", currentDesiredState=" + sch.getStackVersion()
+                + ", newDesiredVersion=" + sch.getDesiredStackVersion());
+            //TODO Create NOP tasks for progress tracking
+            continue;
+          }
+
+          sch.setState(State.UPGRADING);
+          sch.setDesiredState(newState);
+          if (!changedScHosts.containsKey(sc.getName())) {
+            changedScHosts.put(sc.getName(),
+                new HashMap<State, List<ServiceComponentHost>>());
+          }
+          changedScHosts.get(sc.getName()).put(newState,
+              new ArrayList<ServiceComponentHost>());
+          changedScHosts.get(sc.getName()).get(newState).add(sch);
+
+          LOG.info("Handling update to ServiceComponentHost"
+              + ", clusterName=" + request.getClusterName()
+              + ", serviceName=" + service.getName()
+              + ", componentName=" + sc.getName()
+              + ", hostname=" + sch.getHostName()
+              + ", currentState=" + currSchState
+              + ", newDesiredState=" + newState);
+        }
+      }
+    }
+  }
+
+  private boolean checkIfActiveComponentsExist(Cluster c) {
+    boolean activeComponentExists = false;
+    for (Service service : c.getServices().values()) {
+      if (activeComponentExists || service.getDesiredState() != State.INSTALLED) {
+        activeComponentExists = true;
+        break;
+      }
+      for (ServiceComponent component : service.getServiceComponents().values()) {
+        if (activeComponentExists || component.getDesiredState() != State.INSTALLED) {
+          activeComponentExists = true;
+          break;
+        }
+        for (ServiceComponentHost componentHost : component.getServiceComponentHosts().values()) {
+          if (activeComponentExists || componentHost.getDesiredState() != State.INSTALLED) {
+            activeComponentExists = true;
+            break;
+          }
+        }
+      }
+    }
+    return activeComponentExists;
+  }
+
   // FIXME refactor code out of all update functions
   /*
   private TrackActionResponse triggerStateChange(State newState, Service s,
@@ -1459,7 +1661,8 @@ public class AmbariManagementControllerI
   private RequestStatusResponse doStageCreation(Cluster cluster,
       Map<State, List<Service>> changedServices,
       Map<State, List<ServiceComponent>> changedComps,
-      Map<String, Map<State, List<ServiceComponentHost>>> changedScHosts)
+      Map<String, Map<State, List<ServiceComponentHost>>> changedScHosts,
+      Map<String, String> requestParameters)
           throws AmbariException {
 
     // TODO handle different transitions?
@@ -1591,6 +1794,12 @@ public class AmbariManagementControllerI
                   event = new ServiceComponentHostStopEvent(
                       scHost.getServiceComponentName(), scHost.getHostName(),
                       nowTimestamp);
+                } else if (oldSchState == State.UPGRADE_FAILED
+                    || oldSchState == State.UPGRADING) {
+                  roleCommand = RoleCommand.UPGRADE;
+                  event = new ServiceComponentHostUpgradeEvent(
+                      scHost.getServiceComponentName(), scHost.getHostName(),
+                      nowTimestamp, scHost.getDesiredStackVersion().getStackId());
                 } else {
                   throw new AmbariException("Invalid transition for"
                       + " servicecomponenthost"
@@ -1701,7 +1910,7 @@ public class AmbariManagementControllerI
               configurations.get("global").put("rca_enabled", "false");
             }
             createHostAction(cluster, stage, scHost, configurations,
-                roleCommand, nowTimestamp, event);
+                roleCommand, requestParameters, event);
           }
         }
       }
@@ -1814,7 +2023,9 @@ public class AmbariManagementControllerI
             || oldState == State.STARTED
             || oldState == State.START_FAILED
             || oldState == State.INSTALL_FAILED
-            || oldState == State.STOP_FAILED) {
+            || oldState == State.STOP_FAILED
+            || oldState == State.UPGRADE_FAILED
+            || oldState == State.UPGRADING) {
           return true;
         }
         break;
@@ -2082,7 +2293,7 @@ public class AmbariManagementControllerI
             continue;
           }
           /** 
-           * This is hack for now wherein we dont fail if the 
+           * This is hack for now wherein we don't fail if the
            * sch is in INSTALL_FAILED 
            */
           if (!isValidStateTransition(oldSchState, newState)) {
@@ -2171,7 +2382,7 @@ public class AmbariManagementControllerI
     Cluster cluster = clusters.getCluster(clusterNames.iterator().next());
 
     return doStageCreation(cluster, changedServices,
-        changedComps, changedScHosts);
+        changedComps, changedScHosts, null);
   }
 
   @Override
@@ -2430,7 +2641,7 @@ public class AmbariManagementControllerI
     Cluster cluster = clusters.getCluster(clusterNames.iterator().next());
 
     return doStageCreation(cluster, null,
-        changedComps, changedScHosts);
+        changedComps, changedScHosts, null);
   }
 
   @Override
@@ -2715,7 +2926,7 @@ public class AmbariManagementControllerI
     Cluster cluster = clusters.getCluster(clusterNames.iterator().next());
 
     return doStageCreation(cluster, null,
-        null, changedScHosts);
+        null, changedScHosts, null);
   }
 
   @Override

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/metadata/RoleCommandOrder.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/metadata/RoleCommandOrder.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/metadata/RoleCommandOrder.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/metadata/RoleCommandOrder.java Fri Mar  1 23:08:02 2013
@@ -65,8 +65,16 @@ public class RoleCommandOrder {
    */
   private static Map<RoleCommandPair, Set<RoleCommandPair>> dependencies = new HashMap<RoleCommandPair, Set<RoleCommandPair>>();
 
+  /**
+   * Add a pair of tuples where the tuple defined by the first two parameters are blocked on
+   * the tuple defined by the last two pair.
+   * @param blockedRole Role that is blocked
+   * @param blockedCommand The command on the role that is blocked
+   * @param blockerRole The role that is blocking
+   * @param blockerCommand The command on the blocking role
+   */
   private static void addDependency(Role blockedRole,
-      RoleCommand blockedCommand, Role blockerRole, RoleCommand blockerCommand) {
+       RoleCommand blockedCommand, Role blockerRole, RoleCommand blockerCommand) {
     RoleCommandPair rcp1 = new RoleCommandPair(blockedRole, blockedCommand);
     RoleCommandPair rcp2 = new RoleCommandPair(blockerRole, blockerCommand);
     if (dependencies.get(rcp1) == null) {
@@ -167,7 +175,60 @@ public class RoleCommandOrder {
         Role.JOBTRACKER, RoleCommand.STOP);
     addDependency(Role.DATANODE, RoleCommand.STOP,
         Role.TASKTRACKER, RoleCommand.STOP);
-  }
+
+    addDependency(Role.SECONDARY_NAMENODE, RoleCommand.UPGRADE,
+        Role.NAMENODE, RoleCommand.UPGRADE);
+    addDependency(Role.DATANODE, RoleCommand.UPGRADE,
+        Role.SECONDARY_NAMENODE, RoleCommand.UPGRADE);
+    addDependency(Role.HDFS_CLIENT, RoleCommand.UPGRADE,
+        Role.DATANODE, RoleCommand.UPGRADE);
+    addDependency(Role.JOBTRACKER, RoleCommand.UPGRADE,
+        Role.HDFS_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.TASKTRACKER, RoleCommand.UPGRADE,
+        Role.JOBTRACKER, RoleCommand.UPGRADE);
+    addDependency(Role.MAPREDUCE_CLIENT, RoleCommand.UPGRADE,
+        Role.TASKTRACKER, RoleCommand.UPGRADE);
+    addDependency(Role.MAPREDUCE_CLIENT, RoleCommand.UPGRADE,
+        Role.TASKTRACKER, RoleCommand.UPGRADE);
+    addDependency(Role.ZOOKEEPER_SERVER, RoleCommand.UPGRADE,
+        Role.MAPREDUCE_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.ZOOKEEPER_CLIENT, RoleCommand.UPGRADE,
+        Role.ZOOKEEPER_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.HBASE_MASTER, RoleCommand.UPGRADE,
+        Role.ZOOKEEPER_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.HBASE_REGIONSERVER, RoleCommand.UPGRADE,
+        Role.HBASE_MASTER, RoleCommand.UPGRADE);
+    addDependency(Role.HBASE_CLIENT, RoleCommand.UPGRADE,
+        Role.HBASE_REGIONSERVER, RoleCommand.UPGRADE);
+    addDependency(Role.HIVE_SERVER, RoleCommand.UPGRADE,
+        Role.HBASE_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.HIVE_METASTORE, RoleCommand.UPGRADE,
+        Role.HIVE_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.MYSQL_SERVER, RoleCommand.UPGRADE,
+        Role.HIVE_METASTORE, RoleCommand.UPGRADE);
+    addDependency(Role.HIVE_CLIENT, RoleCommand.UPGRADE,
+        Role.MYSQL_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.HCAT, RoleCommand.UPGRADE,
+        Role.HIVE_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.OOZIE_SERVER, RoleCommand.UPGRADE,
+        Role.HCAT, RoleCommand.UPGRADE);
+    addDependency(Role.OOZIE_CLIENT, RoleCommand.UPGRADE,
+        Role.OOZIE_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.WEBHCAT_SERVER, RoleCommand.UPGRADE,
+        Role.OOZIE_CLIENT, RoleCommand.UPGRADE);
+    addDependency(Role.PIG, RoleCommand.UPGRADE,
+        Role.WEBHCAT_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.SQOOP, RoleCommand.UPGRADE,
+        Role.PIG, RoleCommand.UPGRADE);
+    addDependency(Role.NAGIOS_SERVER, RoleCommand.UPGRADE,
+        Role.SQOOP, RoleCommand.UPGRADE);
+    addDependency(Role.GANGLIA_SERVER, RoleCommand.UPGRADE,
+        Role.NAGIOS_SERVER, RoleCommand.UPGRADE);
+    addDependency(Role.GANGLIA_MONITOR, RoleCommand.UPGRADE,
+        Role.GANGLIA_SERVER, RoleCommand.UPGRADE);
+
+    extendTransitiveDependency();
+    }
 
   /**
    * Returns the dependency order. -1 => rgn1 before rgn2, 0 => they can be
@@ -193,6 +254,37 @@ public class RoleCommandOrder {
     return 0;
   }
 
+  /**
+   * Adds transitive dependencies to each node.
+   * A => B and B => C implies A => B,C and B => C
+   */
+  private static void extendTransitiveDependency() {
+    for (RoleCommandPair rcp : dependencies.keySet()) {
+      HashSet<RoleCommandPair> visited = new HashSet<RoleCommandPair>();
+      HashSet<RoleCommandPair> transitiveDependencies = new HashSet<RoleCommandPair>();
+      for (RoleCommandPair directlyBlockedOn : dependencies.get(rcp)) {
+        visited.add(directlyBlockedOn);
+        identifyTransitiveDependencies(directlyBlockedOn, visited, transitiveDependencies);
+      }
+      if (transitiveDependencies.size() > 0) {
+        dependencies.get(rcp).addAll(transitiveDependencies);
+      }
+    }
+  }
+
+  private static void identifyTransitiveDependencies(RoleCommandPair rcp, HashSet<RoleCommandPair> visited,
+                                                     HashSet<RoleCommandPair> transitiveDependencies) {
+    if (dependencies.get(rcp) != null) {
+      for (RoleCommandPair blockedOn : dependencies.get(rcp)) {
+        if (!visited.contains(blockedOn)) {
+          visited.add(blockedOn);
+          transitiveDependencies.add(blockedOn);
+          identifyTransitiveDependencies(blockedOn, visited, transitiveDependencies);
+        }
+      }
+    }
+  }
+
   private int compareCommands(RoleGraphNode rgn1, RoleGraphNode rgn2) {
     RoleCommand rc1 = rgn1.getCommand();
     RoleCommand rc2 = rgn2.getCommand();

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java Fri Mar  1 23:08:02 2013
@@ -95,6 +95,8 @@ public interface Service {
     SQOOP,
     NAGIOS,
     GANGLIA,
-    ZOOKEEPER
+    ZOOKEEPER,
+    PIG,
+    HCATALOG
   }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEvent.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEvent.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEvent.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEvent.java Fri Mar  1 23:08:02 2013
@@ -133,6 +133,8 @@ public abstract class ServiceComponentHo
         return new ServiceComponentHostUninstallEvent(serviceComponentName, hostName, opTimestamp);
       case HOST_SVCCOMP_WIPEOUT:
         return new ServiceComponentHostWipeoutEvent(serviceComponentName, hostName, opTimestamp);
+      case HOST_SVCCOMP_UPGRADE:
+        return new ServiceComponentHostUpgradeEvent(serviceComponentName, hostName, opTimestamp, stackId);
     }
     return null;
   }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java Fri Mar  1 23:08:02 2013
@@ -54,5 +54,9 @@ public enum ServiceComponentHostEventTyp
   /**
    * Triggering a wipe-out ( restore to clean state ).
    */
-  HOST_SVCCOMP_WIPEOUT
+  HOST_SVCCOMP_WIPEOUT,
+  /**
+   * Triggering a host component upgrade.
+   */
+  HOST_SVCCOMP_UPGRADE
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java Fri Mar  1 23:08:02 2013
@@ -104,15 +104,14 @@ public class ServiceInfo {
     StringBuilder sb = new StringBuilder();
     sb.append("Service name:" + name + "\nversion:" + version +
         "\nuser:" + user + "\ncomment:" + comment);
-//    if(properties != null)
-//    for (PropertyInfo property : properties) {
-//      sb.append("\tProperty name=" + property.getName() +
+    //for (PropertyInfo property : getProperties()) {
+    //  sb.append("\tProperty name=" + property.getName() +
     //"\nproperty value=" + property.getValue() + "\ndescription=" + property.getDescription());
-//    }
-    for(ComponentInfo component : components){
+    //}
+    for (ComponentInfo component : getComponents()) {
       sb.append("\n\n\nComponent:\n");
-      sb.append("name="+ component.getName());
-      sb.append("\tcategory="+ component.getCategory() );
+      sb.append("name=" + component.getName());
+      sb.append("\tcategory=" + component.getCategory());
     }
 
     return sb.toString();

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java Fri Mar  1 23:08:02 2013
@@ -18,7 +18,7 @@
 
 package org.apache.ambari.server.state;
 
-public class StackId {
+public class StackId implements Comparable<StackId> {
   private String stackName;
   private String stackVersion;
 
@@ -88,6 +88,39 @@ public class StackId {
     return result;
   }
 
+  @Override
+  public int compareTo(StackId other) {
+    if (this == other) {
+      return 0;
+    }
+
+    if (other == null) {
+      throw new RuntimeException("Cannot compare with a null value.");
+    }
+
+    int returnValue = getStackName().compareTo(other.getStackName());
+    if (returnValue == 0) {
+      String[] thisVersionParts = getStackVersion().split("\\.");
+      String[] thatVersionParts = other.getStackVersion().split("\\.");
+      int length = Math.max(thisVersionParts.length, thatVersionParts.length);
+      for (int i = 0; i < length; i++) {
+        int stack1Part = i < thisVersionParts.length ?
+            Integer.parseInt(thisVersionParts[i]) : 0;
+        int stack2Part = i < thatVersionParts.length ?
+            Integer.parseInt(thatVersionParts[i]) : 0;
+        if (stack1Part < stack2Part) {
+          return -1;
+        }
+        if (stack1Part > stack2Part) {
+          return 1;
+        }
+      }
+    } else {
+      throw new RuntimeException("StackId with different names cannot be compared.");
+    }
+    return returnValue;
+  }
+
   public String toString() {
     return getStackId();
   }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/State.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/State.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/State.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/State.java Fri Mar  1 23:08:02 2013
@@ -20,7 +20,7 @@ package org.apache.ambari.server.state;
 
 public enum State {
   /**
-   * Initial/Clean state
+   * Initial/Clean state.
    */
   INIT(0),
   /**
@@ -28,11 +28,11 @@ public enum State {
    */
   INSTALLING(1),
   /**
-   * Install failed
+   * Install failed.
    */
   INSTALL_FAILED(2),
   /**
-   * State when install completed successfully
+   * State when install completed successfully.
    */
   INSTALLED(3),
   /**
@@ -52,10 +52,9 @@ public enum State {
    */
   STOPPING(7),
   /**
-   * Stop failed
+   * Stop failed.
    */
   STOP_FAILED(8),
-
   /**
    * In the process of uninstalling.
    */
@@ -69,13 +68,21 @@ public enum State {
    */
   UNINSTALLED(11),
   /**
-   * In the process of wiping out the install
+   * In the process of wiping out the install.
    */
   WIPING_OUT(12),
   /**
-   * State when wipeout fails
+   * State when wipeout fails.
+   */
+  WIPEOUT_FAILED(13),
+  /**
+   * In the process of upgrading the deployed bits.
    */
-  WIPEOUT_FAILED(13);
+  UPGRADING(14),
+  /**
+   * Upgrade has failed.
+   */
+  UPGRADE_FAILED(15);
 
   private final int state;
 
@@ -83,6 +90,11 @@ public enum State {
     this.state = state;
   }
 
+  /**
+   * Indicates whether or not it is a valid desired state.
+   *
+   * @return true if this is a valid desired state.
+   */
   public boolean isValidDesiredState() {
     switch (State.values()[this.state]) {
       case INIT:
@@ -95,6 +107,11 @@ public enum State {
     }
   }
 
+  /**
+   * Indicates whether or not its a state indicating a task in progress.
+   *
+   * @return true if this is a state indicating progress.
+   */
   public boolean isInProgressState() {
     switch (State.values()[this.state]) {
       case INSTALLING:
@@ -102,12 +119,18 @@ public enum State {
       case STOPPING:
       case UNINSTALLING:
       case WIPING_OUT:
+      case UPGRADING:
         return true;
       default:
         return false;
     }
   }
 
+  /**
+   * Indicates whether or not it is a valid state for the client component.
+   *
+   * @return true if this is a valid state for a client component.
+   */
   public boolean isValidClientComponentState() {
     switch (State.values()[this.state]) {
       case STARTING:
@@ -122,8 +145,7 @@ public enum State {
   }
 
   /**
-   * Indicates whether or not the resource with this state
-   * can be removed.
+   * Indicates whether or not the resource with this state can be removed.
    *
    * @return true if this is a removable state
    */
@@ -133,10 +155,11 @@ public enum State {
       case INSTALLING:
       case INSTALLED:
       case INSTALL_FAILED:
+      case UPGRADE_FAILED:
       case UNINSTALLED:
         return true;
       default:
         return false;
     }
   }
-}
+}
\ No newline at end of file

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java Fri Mar  1 23:08:02 2013
@@ -490,6 +490,7 @@ public class ClusterImpl implements Clus
           clusterEntity = clusterDAO.merge(clusterEntity);
         } else {
           clusterStateEntity.setCurrentStackVersion(gson.toJson(stackVersion));
+          clusterStateDAO.merge(clusterStateEntity);
         }
     } catch (RollbackException e) {
       LOG.warn("Unable to set version " + stackVersion + " for cluster " + getClusterName());

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java Fri Mar  1 23:08:02 2013
@@ -247,6 +247,27 @@ public class ServiceComponentHostImpl im
          ServiceComponentHostEventType.HOST_SVCCOMP_OP_FAILED,
          new ServiceComponentHostOpCompletedTransition())
 
+     .addTransition(State.UPGRADING,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_IN_PROGRESS,
+         new ServiceComponentHostOpInProgressTransition())
+     .addTransition(State.UPGRADING,
+         State.INSTALLED,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_SUCCEEDED,
+         new ServiceComponentHostOpCompletedTransition())
+     .addTransition(State.UPGRADING,
+         State.UPGRADE_FAILED,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_FAILED,
+         new ServiceComponentHostOpCompletedTransition())
+     .addTransition(State.UPGRADE_FAILED,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_UPGRADE,
+         new ServiceComponentHostOpStartedTransition())
+     .addTransition(State.UPGRADING,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_UPGRADE,
+         new ServiceComponentHostOpInProgressTransition())
+
      .addTransition(State.UNINSTALL_FAILED,
          State.UNINSTALLING,
          ServiceComponentHostEventType.HOST_SVCCOMP_OP_RESTART,
@@ -349,6 +370,27 @@ public class ServiceComponentHostImpl im
          ServiceComponentHostEventType.HOST_SVCCOMP_INSTALL,
          new ServiceComponentHostOpStartedTransition())
 
+     .addTransition(State.UPGRADING,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_IN_PROGRESS,
+         new ServiceComponentHostOpInProgressTransition())
+     .addTransition(State.UPGRADING,
+         State.INSTALLED,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_SUCCEEDED,
+         new ServiceComponentHostOpCompletedTransition())
+     .addTransition(State.UPGRADING,
+         State.UPGRADE_FAILED,
+         ServiceComponentHostEventType.HOST_SVCCOMP_OP_FAILED,
+         new ServiceComponentHostOpCompletedTransition())
+     .addTransition(State.UPGRADE_FAILED,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_UPGRADE,
+         new ServiceComponentHostOpStartedTransition())
+     .addTransition(State.UPGRADING,
+         State.UPGRADING,
+         ServiceComponentHostEventType.HOST_SVCCOMP_UPGRADE,
+         new ServiceComponentHostOpInProgressTransition())
+
      .addTransition(State.UNINSTALLING,
          State.UNINSTALLING,
          ServiceComponentHostEventType.HOST_SVCCOMP_OP_IN_PROGRESS,

Added: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostUpgradeEvent.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostUpgradeEvent.java?rev=1451761&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostUpgradeEvent.java (added)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostUpgradeEvent.java Fri Mar  1 23:08:02 2013
@@ -0,0 +1,33 @@
+/**
+ * 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.svccomphost;
+
+import org.apache.ambari.server.state.ServiceComponentHostEvent;
+import org.apache.ambari.server.state.ServiceComponentHostEventType;
+
+public class ServiceComponentHostUpgradeEvent extends
+    ServiceComponentHostEvent {
+
+
+  public ServiceComponentHostUpgradeEvent(String serviceComponentName,
+      String hostName, long opTimestamp, String stackId) {
+    super(ServiceComponentHostEventType.HOST_SVCCOMP_UPGRADE,
+        serviceComponentName, hostName, opTimestamp, stackId);
+  }
+}

Added: incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql?rev=1451761&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql (added)
+++ incubator/ambari/trunk/ambari-server/src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql Fri Mar  1 23:08:02 2013
@@ -0,0 +1,21 @@
+--
+-- 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.
+--
+\connect ambari;
+
+ALTER TABLE ambari.clusterstate
+  ADD COLUMN current_stack_version VARCHAR(255) NOT NULL;

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java Fri Mar  1 23:08:02 2013
@@ -601,6 +601,96 @@ public class TestHeartbeatHandler {
   }
 
   @Test
+  public void testUpgradeSpecificHandling() throws AmbariException, InvalidStateTransitionException {
+    ActionManager am = new ActionManager(0, 0, null, null,
+        new ActionDBInMemoryImpl(), new HostsMap((String) null));
+    Cluster cluster = getDummyCluster();
+
+    @SuppressWarnings("serial")
+    Set<String> hostNames = new HashSet<String>() {{
+      add(DummyHostname1);
+    }};
+    clusters.mapHostsToCluster(hostNames, DummyCluster);
+    Service hdfs = cluster.addService(HDFS);
+    hdfs.persist();
+    hdfs.addServiceComponent(DATANODE).persist();
+    hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
+
+    ActionQueue aq = new ActionQueue();
+    HeartBeatHandler handler = getHeartBeatHandler(am, aq);
+
+    ServiceComponentHost serviceComponentHost1 = clusters.getCluster(DummyCluster).getService(HDFS).
+        getServiceComponent(DATANODE).getServiceComponentHost(DummyHostname1);
+    serviceComponentHost1.setState(State.UPGRADING);
+
+    HeartBeat hb = new HeartBeat();
+    hb.setTimestamp(System.currentTimeMillis());
+    hb.setResponseId(0);
+    hb.setHostname(DummyHostname1);
+    hb.setNodeStatus(new HostStatus(Status.HEALTHY, DummyHostStatus));
+
+    List<CommandReport> reports = new ArrayList<CommandReport>();
+    CommandReport cr = new CommandReport();
+    cr.setActionId(StageUtils.getActionId(requestId, stageId));
+    cr.setTaskId(1);
+    cr.setClusterName(DummyCluster);
+    cr.setServiceName(HDFS);
+    cr.setRole(DATANODE);
+    cr.setStatus(HostRoleStatus.IN_PROGRESS.toString());
+    cr.setStdErr("none");
+    cr.setStdOut("dummy output");
+    cr.setExitCode(777);
+    reports.add(cr);
+    hb.setReports(reports);
+    hb.setComponentStatus(new ArrayList<ComponentStatus>());
+
+    handler.handleHeartBeat(hb);
+    assertEquals("Host state should  be " + State.UPGRADING,
+        State.UPGRADING, serviceComponentHost1.getState());
+
+    hb.setTimestamp(System.currentTimeMillis());
+    hb.setResponseId(1);
+    cr.setStatus(HostRoleStatus.COMPLETED.toString());
+    cr.setExitCode(0);
+
+    handler.handleHeartBeat(hb);
+    assertEquals("Host state should be " + State.INSTALLED,
+        State.INSTALLED, serviceComponentHost1.getState());
+
+    serviceComponentHost1.setState(State.UPGRADING);
+    hb.setTimestamp(System.currentTimeMillis());
+    hb.setResponseId(2);
+    cr.setStatus(HostRoleStatus.FAILED.toString());
+    cr.setExitCode(3);
+
+    handler.handleHeartBeat(hb);
+    assertEquals("Host state should be " + State.UPGRADE_FAILED,
+        State.UPGRADE_FAILED, serviceComponentHost1.getState());
+
+    // TODO What happens when there is a TIMEDOUT
+
+    serviceComponentHost1.setState(State.UPGRADING);
+    hb.setTimestamp(System.currentTimeMillis());
+    hb.setResponseId(3);
+    cr.setStatus(HostRoleStatus.PENDING.toString());
+    cr.setExitCode(55);
+
+    handler.handleHeartBeat(hb);
+    assertEquals("Host state should be " + State.UPGRADING,
+        State.UPGRADING, serviceComponentHost1.getState());
+
+    serviceComponentHost1.setState(State.UPGRADING);
+    hb.setTimestamp(System.currentTimeMillis());
+    hb.setResponseId(4);
+    cr.setStatus(HostRoleStatus.QUEUED.toString());
+    cr.setExitCode(55);
+
+    handler.handleHeartBeat(hb);
+    assertEquals("Host state should be " + State.UPGRADING,
+        State.UPGRADING, serviceComponentHost1.getState());
+  }
+
+  @Test
   public void testStatusHeartbeatWithVersion() throws Exception {
     ActionManager am = new ActionManager(0, 0, null, null,
         new ActionDBInMemoryImpl(), new HostsMap((String) null));

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java?rev=1451761&r1=1451760&r2=1451761&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java Fri Mar  1 23:08:02 2013
@@ -44,6 +44,7 @@ import org.apache.ambari.server.actionma
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
@@ -68,6 +69,7 @@ import org.apache.ambari.server.utils.St
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -1656,7 +1658,7 @@ public class AmbariManagementControllerT
 
     try {
       r = new ServiceRequest(c2.getClusterName(), s1.getName(), null, null);
-      resp = controller.getServices(Collections.singleton(r));
+      controller.getServices(Collections.singleton(r));
       fail("Expected failure for invalid service");
     } catch (Exception e) {
       // Expected
@@ -3235,8 +3237,7 @@ public class AmbariManagementControllerT
       Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
       requests.add(r);
 
-      RequestStatusResponse trackAction =
-              controller.updateServices(requests);
+      controller.updateServices(requests);
       Assert.assertEquals(State.INSTALLED,
               clusters.getCluster(clusterName).getService(serviceName)
                       .getDesiredState());
@@ -3255,7 +3256,7 @@ public class AmbariManagementControllerT
               State.STARTED.toString());
       requests.clear();
       requests.add(r);
-      trackAction = controller.updateServices(requests);
+      controller.updateServices(requests);
 
       // manually change live state to started as no running action manager
       for (ServiceComponent sc :
@@ -3781,4 +3782,380 @@ public class AmbariManagementControllerT
     Assert.assertEquals(Role.PIG_SERVICE_CHECK.toString(),
         taskStatuses.get(0).getRole());
   }
+
+  @Test
+  public void testUpdateClusterVersionBasic() throws AmbariException {
+    String clusterName = "foo1";
+    String serviceName = "PIG";
+    String host1 = "h1";
+    String host2 = "h2";
+    String componentName = "PIG";
+    StackId currentStackId = new StackId("HDP-0.1");
+
+    createCluster(clusterName);
+    Cluster c = clusters.getCluster(clusterName);
+    c.setDesiredStackVersion(currentStackId);
+    createService(clusterName, serviceName, State.INIT);
+    createServiceComponent(clusterName, serviceName, componentName, null);
+
+    clusters.addHost(host1);
+    clusters.getHost(host1).persist();
+    clusters.addHost(host2);
+    clusters.getHost(host2).persist();
+
+    clusters.getHost(host1).setOsType("centos5");
+    clusters.getHost(host2).setOsType("centos6");
+    clusters.mapHostToCluster(host1, clusterName);
+    clusters.mapHostToCluster(host2, clusterName);
+
+    createServiceComponentHost(clusterName, null, componentName,
+        host1, null);
+    createServiceComponentHost(clusterName, null, componentName,
+        host2, null);
+
+    c.getService(serviceName).setDesiredState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).setDesiredState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host1)
+        .setDesiredState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host2)
+        .setDesiredState(State.STARTED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host1)
+        .setStackVersion(currentStackId);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host2)
+        .setStackVersion(currentStackId);
+
+    ClusterRequest r = new ClusterRequest(c.getClusterId(), clusterName, "HDP-0.0.1", null);
+    try {
+      controller.updateCluster(r);
+      fail("Update cluster creation should fail");
+    } catch (AmbariException e) {
+      Assert.assertTrue(e.getMessage().contains("must be greater than current version"));
+    }
+
+    r = new ClusterRequest(c.getClusterId(), clusterName, "HDPLocal-1.2.2", null);
+    try {
+      controller.updateCluster(r);
+      fail("Update cluster creation should fail");
+    } catch (AmbariException e) {
+      Assert.assertTrue(e.getMessage().contains("Upgrade not possible between different stacks"));
+    }
+
+    r = new ClusterRequest(c.getClusterId(), clusterName, "HDP-0.2", null);
+    try {
+      controller.updateCluster(r);
+      fail("Update cluster creation should fail");
+    } catch (AmbariException e) {
+      Assert.assertTrue(e.getMessage().contains("Upgrade needs all services to be stopped"));
+    }
+
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host2)
+        .setDesiredState(State.INSTALLED);
+    controller.updateCluster(r);
+    StackId expectedStackId = new StackId("HDP-0.2");
+    Assert.assertTrue(expectedStackId.equals(c.getDesiredStackVersion()));
+    Assert.assertTrue(expectedStackId.equals(c.getService(serviceName).getDesiredStackVersion()));
+    Assert.assertTrue(expectedStackId.equals(c.getService(serviceName)
+        .getServiceComponent(componentName).getDesiredStackVersion()));
+    Assert.assertTrue(expectedStackId.equals(c.getService(serviceName)
+        .getServiceComponent(componentName).getServiceComponentHost(host1).getDesiredStackVersion()));
+    Assert.assertTrue(expectedStackId.equals(c.getService(serviceName)
+        .getServiceComponent(componentName).getServiceComponentHost(host2).getDesiredStackVersion()));
+    Assert.assertTrue(currentStackId.equals(c.getService(serviceName)
+        .getServiceComponent(componentName).getServiceComponentHost(host1).getStackVersion()));
+    Assert.assertTrue(currentStackId.equals(c.getService(serviceName)
+        .getServiceComponent(componentName).getServiceComponentHost(host2).getStackVersion()));
+    ServiceComponent sc = c.getService(serviceName).getServiceComponent(componentName);
+    Assert.assertEquals(State.UPGRADING, sc.getServiceComponentHost(host1).getState());
+    Assert.assertEquals(State.UPGRADING, sc.getServiceComponentHost(host2).getState());
+
+    // cases where there is no update required
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host1)
+        .setDesiredState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host2)
+        .setDesiredState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host1)
+        .setState(State.INSTALLED);
+    c.getService(serviceName).getServiceComponent(componentName).getServiceComponentHost(host2)
+        .setState(State.INSTALLED);
+    c.setCurrentStackVersion(expectedStackId);
+    r = new ClusterRequest(c.getClusterId(), clusterName, "", null);
+    controller.updateCluster(r);
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host1).getState());
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host2).getState());
+
+    r = new ClusterRequest(c.getClusterId(), clusterName, null, null);
+    controller.updateCluster(r);
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host1).getState());
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host2).getState());
+
+    r = new ClusterRequest(c.getClusterId(), clusterName, "HDP-0.2", null);
+    controller.updateCluster(r);
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host1).getState());
+    Assert.assertEquals(State.INSTALLED, sc.getServiceComponentHost(host2).getState());
+  }
+
+  @Test
+  public void testUpdateClusterVersionCombinations() throws AmbariException {
+    String clusterName = "foo1";
+    String pigServiceName = "PIG";
+    String mrServiceName = "MAPREDUCE";
+    String host1 = "h1";
+    String host2 = "h2";
+    String pigComponentName = "PIG";
+    String mrJobTrackerComp = "JOBTRACKER";
+    String mrTaskTrackerComp = "TASKTRACKER";
+    String mrClientComp = "MAPREDUCE_CLIENT";
+    String hdfsService = "HDFS";
+    String hdfsNameNode = "NAMENODE";
+    String hdfsDataNode = "DATANODE";
+    String hdfsClient = "HDFS_CLIENT";
+    StackId currentStackId = new StackId("HDP-0.1");
+    StackId desiredStackId = new StackId("HDP-0.2");
+    List<String> hosts = new ArrayList<String>();
+    hosts.add(host1);
+    hosts.add(host2);
+
+    createCluster(clusterName);
+    Cluster c = clusters.getCluster(clusterName);
+    c.setDesiredStackVersion(currentStackId);
+    createService(clusterName, pigServiceName, State.INIT);
+    createServiceComponent(clusterName, pigServiceName, pigComponentName, null);
+
+    clusters.addHost(host1);
+    clusters.getHost(host1).persist();
+    clusters.addHost(host2);
+    clusters.getHost(host2).persist();
+
+    clusters.getHost(host1).setOsType("centos5");
+    clusters.getHost(host2).setOsType("centos6");
+    clusters.mapHostToCluster(host1, clusterName);
+    clusters.mapHostToCluster(host2, clusterName);
+
+    createServiceComponentHost(clusterName, null, pigComponentName,
+        host1, null);
+    createServiceComponentHost(clusterName, null, pigComponentName,
+        host2, null);
+
+    resetServiceState(pigServiceName, currentStackId, c);
+
+    ClusterRequest r = new ClusterRequest(c.getClusterId(), clusterName, "HDP-0.2", null);
+    RequestStatusResponse trackAction = controller.updateCluster(r);
+    List<Stage> stages = actionDB.getAllStages(trackAction.getRequestId());
+
+    // Upgrade a cluster with one service
+    ExpectedUpgradeTasks expectedTasks = new ExpectedUpgradeTasks(hosts);
+    expectedTasks.expectTask(Role.PIG, host1);
+    expectedTasks.expectTask(Role.PIG, host2);
+    validateGeneratedStages(stages, 1, expectedTasks);
+
+    resetCluster(c, currentStackId);
+
+    createService(clusterName, mrServiceName, State.INIT);
+    createServiceComponent(clusterName, mrServiceName, mrJobTrackerComp, null);
+    createServiceComponent(clusterName, mrServiceName, mrTaskTrackerComp, null);
+    createServiceComponent(clusterName, mrServiceName, mrClientComp, null);
+
+    createServiceComponentHost(clusterName, null, mrJobTrackerComp, host1, null);
+    createServiceComponentHost(clusterName, null, mrTaskTrackerComp, host2, null);
+    createServiceComponentHost(clusterName, null, mrClientComp, host2, null);
+
+    resetServiceState(mrServiceName, currentStackId, c);
+
+    // Upgrade a cluster with two service
+    r = new ClusterRequest(c.getClusterId(), clusterName, "HDP-0.2", null);
+    trackAction = controller.updateCluster(r);
+    stages = actionDB.getAllStages(trackAction.getRequestId());
+
+    expectedTasks.expectTask(Role.JOBTRACKER, host1);
+    expectedTasks.expectTask(Role.TASKTRACKER, host2);
+    expectedTasks.expectTask(Role.MAPREDUCE_CLIENT, host2);
+    validateGeneratedStages(stages, 4, expectedTasks);
+
+    // Upgrade again
+    trackAction = controller.updateCluster(r);
+    stages = actionDB.getAllStages(trackAction.getRequestId());
+    validateGeneratedStages(stages, 4, expectedTasks);
+
+    // some host components are upgraded
+    c.getService(pigServiceName).getServiceComponent(pigComponentName).getServiceComponentHost(host1)
+        .setState(State.INSTALLED);
+    c.getService(pigServiceName).getServiceComponent(pigComponentName).getServiceComponentHost(host2)
+        .setState(State.INSTALLED);
+    c.getService(pigServiceName).getServiceComponent(pigComponentName).getServiceComponentHost(host1)
+        .setStackVersion(desiredStackId);
+    c.getService(pigServiceName).getServiceComponent(pigComponentName).getServiceComponentHost(host2)
+        .setStackVersion(desiredStackId);
+
+    trackAction = controller.updateCluster(r);
+    stages = actionDB.getAllStages(trackAction.getRequestId());
+    expectedTasks.resetAll();
+    expectedTasks.expectTask(Role.JOBTRACKER, host1);
+    expectedTasks.expectTask(Role.TASKTRACKER, host2);
+    expectedTasks.expectTask(Role.MAPREDUCE_CLIENT, host2);
+    validateGeneratedStages(stages, 3, expectedTasks);
+
+    c.getService(mrServiceName).getServiceComponent(mrJobTrackerComp).getServiceComponentHost(host1)
+        .setState(State.UPGRADE_FAILED);
+    c.getService(mrServiceName).getServiceComponent(mrTaskTrackerComp).getServiceComponentHost(host2)
+        .setState(State.UPGRADE_FAILED);
+    trackAction = controller.updateCluster(r);
+    stages = actionDB.getAllStages(trackAction.getRequestId());
+    validateGeneratedStages(stages, 3, expectedTasks);
+
+    // Add HDFS and upgrade
+    createService(clusterName, hdfsService, State.INIT);
+    createServiceComponent(clusterName, hdfsService, hdfsNameNode, null);
+    createServiceComponent(clusterName, hdfsService, hdfsDataNode, null);
+    createServiceComponent(clusterName, hdfsService, hdfsClient, null);
+
+    createServiceComponentHost(clusterName, null, hdfsNameNode, host1, null);
+    createServiceComponentHost(clusterName, null, hdfsDataNode, host1, null);
+    createServiceComponentHost(clusterName, null, hdfsDataNode, host2, null);
+    createServiceComponentHost(clusterName, null, hdfsClient, host2, null);
+
+    resetServiceState(hdfsService, currentStackId, c);
+    resetServiceState(mrServiceName, currentStackId, c);
+    resetServiceState(pigServiceName, currentStackId, c);
+
+    trackAction = controller.updateCluster(r);
+    stages = actionDB.getAllStages(trackAction.getRequestId());
+
+    expectedTasks.resetAll();
+    expectedTasks.expectTask(Role.PIG, host1);
+    expectedTasks.expectTask(Role.PIG, host2);
+    expectedTasks.expectTask(Role.JOBTRACKER, host1);
+    expectedTasks.expectTask(Role.TASKTRACKER, host2);
+    expectedTasks.expectTask(Role.MAPREDUCE_CLIENT, host2);
+    expectedTasks.expectTask(Role.DATANODE, host1);
+    expectedTasks.expectTask(Role.DATANODE, host2);
+    expectedTasks.expectTask(Role.NAMENODE, host1);
+    expectedTasks.expectTask(Role.HDFS_CLIENT, host2);
+    validateGeneratedStages(stages, 7, expectedTasks);
+  }
+
+  private void resetServiceState(String hdfsService, StackId currentStackId, Cluster c) throws AmbariException {
+    c.getService(hdfsService).setDesiredState(State.INSTALLED);
+    for (ServiceComponent sc : c.getService(hdfsService).getServiceComponents().values()) {
+      sc.setDesiredState(State.INSTALLED);
+      for (ServiceComponentHost sch : sc.getServiceComponentHosts().values()) {
+        sch.setDesiredState(State.INSTALLED);
+        sch.setState(State.INSTALLED);
+        sch.setStackVersion(currentStackId);
+      }
+    }
+  }
+
+  private void validateGeneratedStages(List<Stage> stages, int expectedStageCount, ExpectedUpgradeTasks expectedTasks) {
+    Assert.assertEquals(expectedStageCount, stages.size());
+    int prevRoleOrder = -1;
+    for (Stage stage : stages) {
+      int currRoleOrder = -1;
+      for (HostRoleCommand command : stage.getOrderedHostRoleCommands()) {
+        Assert.assertTrue(command.toString(), expectedTasks.isTaskExpected(command.getRole(), command.getHostName()));
+        currRoleOrder = expectedTasks.getRoleOrder(command.getRole());
+        ExecutionCommand execCommand = command.getExecutionCommandWrapper().getExecutionCommand();
+        Assert.assertTrue(execCommand.getCommandParams().containsKey("source_stack_version"));
+        Assert.assertTrue(execCommand.getCommandParams().containsKey("target_stack_version"));
+        Assert.assertEquals(RoleCommand.UPGRADE, execCommand.getRoleCommand());
+      }
+
+      List<HostRoleCommand> commands = stage.getOrderedHostRoleCommands();
+      Assert.assertTrue(commands.size() > 0);
+      Role role = commands.get(0).getRole();
+      for (HostRoleCommand command : commands) {
+        Assert.assertTrue("All commands must be for the same role", role.equals(command.getRole()));
+      }
+
+      Assert.assertTrue("Roles must be in order", currRoleOrder > prevRoleOrder);
+      prevRoleOrder = currRoleOrder;
+    }
+  }
+
+  private void resetCluster(Cluster cluster, StackId currentStackId) {
+    cluster.setDesiredStackVersion(currentStackId);
+    for (Service service : cluster.getServices().values()) {
+      service.setDesiredStackVersion(currentStackId);
+      for (ServiceComponent component : service.getServiceComponents().values()) {
+        component.setDesiredStackVersion(currentStackId);
+        for (ServiceComponentHost componentHost : component.getServiceComponentHosts().values()) {
+          componentHost.setDesiredStackVersion(currentStackId);
+          componentHost.setState(State.INSTALLED);
+        }
+      }
+    }
+  }
+
+  class ExpectedUpgradeTasks {
+    private static final int ROLE_COUNT = 24;
+    private ArrayList<Map<String, Boolean>> expectedList;
+    private Map<Role, Integer> roleToIndex;
+
+    public ExpectedUpgradeTasks(List<String> hosts) {
+      roleToIndex = new HashMap<Role, Integer>();
+      expectedList = new ArrayList<Map<String, Boolean>>(ROLE_COUNT);
+
+      fillRoleToIndex();
+      fillExpectedHosts(hosts);
+    }
+
+    public void expectTask(Role role, String host) {
+      expectedList.get(roleToIndex.get(role)).put(host, true);
+    }
+
+    public boolean isTaskExpected(Role role, String host) {
+      return expectedList.get(roleToIndex.get(role)).get(host);
+    }
+
+    public int getRoleOrder(Role role) {
+      return roleToIndex.get(role);
+    }
+
+    public void resetAll() {
+      for (Role role : roleToIndex.keySet()) {
+        Map<String, Boolean> hostState = expectedList.get(roleToIndex.get(role));
+        for (String host : hostState.keySet()) {
+          hostState.put(host, false);
+        }
+      }
+    }
+
+    private void fillExpectedHosts(List<String> hosts) {
+      for (int index = 0; index < ROLE_COUNT; index++) {
+        Map<String, Boolean> hostState = new HashMap<String, Boolean>();
+        for (String host : hosts) {
+          hostState.put(host, false);
+        }
+        expectedList.add(hostState);
+      }
+    }
+
+    private void fillRoleToIndex() {
+      this.roleToIndex.put(Role.NAMENODE, 0);
+      this.roleToIndex.put(Role.SECONDARY_NAMENODE, 1);
+      this.roleToIndex.put(Role.DATANODE, 2);
+      this.roleToIndex.put(Role.HDFS_CLIENT, 3);
+      this.roleToIndex.put(Role.JOBTRACKER, 4);
+      this.roleToIndex.put(Role.TASKTRACKER, 5);
+      this.roleToIndex.put(Role.MAPREDUCE_CLIENT, 6);
+      this.roleToIndex.put(Role.ZOOKEEPER_SERVER, 7);
+      this.roleToIndex.put(Role.ZOOKEEPER_CLIENT, 8);
+      this.roleToIndex.put(Role.HBASE_MASTER, 9);
+
+      this.roleToIndex.put(Role.HBASE_REGIONSERVER, 10);
+      this.roleToIndex.put(Role.HBASE_CLIENT, 11);
+      this.roleToIndex.put(Role.HIVE_SERVER, 12);
+      this.roleToIndex.put(Role.HIVE_METASTORE, 13);
+      this.roleToIndex.put(Role.HIVE_CLIENT, 14);
+      this.roleToIndex.put(Role.HCAT, 15);
+      this.roleToIndex.put(Role.OOZIE_SERVER, 16);
+      this.roleToIndex.put(Role.OOZIE_CLIENT, 17);
+      this.roleToIndex.put(Role.WEBHCAT_SERVER, 18);
+      this.roleToIndex.put(Role.PIG, 19);
+
+      this.roleToIndex.put(Role.SQOOP, 20);
+      this.roleToIndex.put(Role.GANGLIA_SERVER, 21);
+      this.roleToIndex.put(Role.GANGLIA_MONITOR, 22);
+      this.roleToIndex.put(Role.NAGIOS_SERVER, 23);
+    }
+  }
 }

Added: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/RoleGraphTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/RoleGraphTest.java?rev=1451761&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/RoleGraphTest.java (added)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/metadata/RoleGraphTest.java Fri Mar  1 23:08:02 2013
@@ -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.metadata;
+
+import junit.framework.Assert;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.stageplanner.RoleGraphNode;
+import org.junit.Test;
+
+public class RoleGraphTest {
+
+  @Test
+  public void testValidateOrder() {
+    RoleCommandOrder rco = new RoleCommandOrder();
+    RoleCommandOrder.initialize();
+
+    RoleGraphNode datanode_upgrade = new RoleGraphNode(Role.DATANODE, RoleCommand.UPGRADE);
+    RoleGraphNode hdfs_client_upgrade = new RoleGraphNode(Role.HDFS_CLIENT, RoleCommand.UPGRADE);
+    Assert.assertEquals(-1, rco.order(datanode_upgrade, hdfs_client_upgrade));
+    Assert.assertEquals(1, rco.order(hdfs_client_upgrade, datanode_upgrade));
+
+    RoleGraphNode namenode_upgrade = new RoleGraphNode(Role.NAMENODE, RoleCommand.UPGRADE);
+    RoleGraphNode ganglia_server_upgrade = new RoleGraphNode(Role.GANGLIA_SERVER, RoleCommand.UPGRADE);
+    Assert.assertEquals(1, rco.order(ganglia_server_upgrade, hdfs_client_upgrade));
+    Assert.assertEquals(1, rco.order(ganglia_server_upgrade, datanode_upgrade));
+    Assert.assertEquals(-1, rco.order(namenode_upgrade, ganglia_server_upgrade));
+
+    RoleGraphNode datanode_start = new RoleGraphNode(Role.DATANODE, RoleCommand.START);
+    RoleGraphNode datanode_install = new RoleGraphNode(Role.DATANODE, RoleCommand.INSTALL);
+    RoleGraphNode jobtracker_start = new RoleGraphNode(Role.JOBTRACKER, RoleCommand.START);
+    Assert.assertEquals(1, rco.order(datanode_start, datanode_install));
+    Assert.assertEquals(1, rco.order(jobtracker_start, datanode_start));
+
+    Assert.assertEquals(0, rco.order(jobtracker_start, jobtracker_start));
+  }
+}