Repository: ambari
Updated Branches:
  refs/heads/trunk 9f68828eb -> 550563a1c


AMBARI-8778. Rolling Upgrade - Upgrade Pack needs a Cluster Post-Upgrade to 
Finalize (alejandro)


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

Branch: refs/heads/trunk
Commit: 550563a1cb04a8f9a237998511949b2740dcaf36
Parents: 9f68828
Author: Alejandro Fernandez <[email protected]>
Authored: Thu Dec 18 10:35:18 2014 -0800
Committer: Alejandro Fernandez <[email protected]>
Committed: Thu Dec 18 14:18:10 2014 -0800

----------------------------------------------------------------------
 .../internal/UpgradeResourceProvider.java       |   9 +-
 .../upgrades/FinalizeUpgradeAction.java         | 132 +++++++++++++++++++
 .../ambari/server/state/UpgradeHelper.java      |   3 +-
 .../server/state/cluster/ClusterImpl.java       |  29 +++-
 .../state/stack/upgrade/ClusterGrouping.java    |  75 ++++++-----
 .../server/state/stack/upgrade/Grouping.java    |  10 +-
 .../state/stack/upgrade/ServerActionTask.java   |  44 +++++++
 .../stack/upgrade/ServerSideActionTask.java     |   2 -
 .../state/stack/upgrade/StageWrapper.java       |   3 -
 .../ambari/server/state/stack/upgrade/Task.java |  10 +-
 .../stacks/HDP/2.2/upgrades/upgrade-2.2.xml     |  20 +--
 .../ambari/server/state/UpgradeHelperTest.java  |  11 +-
 .../server/state/stack/UpgradePackTest.java     |  11 --
 .../stacks/HDP/2.1.1/upgrades/upgrade_test.xml  |   4 +
 14 files changed, 279 insertions(+), 84 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index c733279..fa39c97 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -619,6 +619,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
 
     Map<String, String> commandParams = new HashMap<String, String>();
     commandParams.put("clusterName", cluster.getClusterName());
+    commandParams.put("version", version);
 
     String itemText = entity.getText();
     switch (task.getType()) {
@@ -640,13 +641,10 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
 
     entity.setText(itemText);
 
-    Map<String, String> restartCommandParams = new HashMap<String, String>();
-    restartCommandParams.put("version", version);
-
     ActionExecutionContext actionContext = new ActionExecutionContext(
         cluster.getClusterName(), Role.AMBARI_SERVER_ACTION.toString(),
         Collections.<RequestResourceFilter>emptyList(),
-        restartCommandParams);
+        commandParams);
     actionContext.setTimeout(Short.valueOf((short)-1));
 
     ExecuteCommandJson jsons = commandExecutionHelper.get().getCommandJson(
@@ -679,8 +677,5 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
         commandParams, 1200);
 
     request.addStages(Collections.singletonList(stage));
-
   }
-
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
new file mode 100644
index 0000000..7894de8
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.serveraction.upgrades;
+
+import com.google.inject.Inject;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.orm.dao.ClusterVersionDAO;
+import org.apache.ambari.server.orm.dao.HostVersionDAO;
+import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.serveraction.AbstractServerAction;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.RepositoryVersionState;
+import org.apache.commons.lang.StringUtils;
+
+import java.text.MessageFormat;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Action that represents finalizing the Upgrade by completing any database 
changes.
+ */
+public class FinalizeUpgradeAction extends AbstractServerAction {
+
+
+  /**
+   * The Cluster that this ServerAction implementation is executing on
+   */
+  @Inject
+  private Clusters clusters = null;
+
+  @Inject
+  private ClusterVersionDAO clusterVersionDAO;
+
+  @Inject
+  private HostVersionDAO hostVersionDAO;
+
+  @Override
+  public CommandReport execute(
+      ConcurrentMap<String, Object> requestSharedDataContext)
+      throws AmbariException, InterruptedException {
+
+    Set<RepositoryVersionState> allowedStates = new 
HashSet<RepositoryVersionState>();
+    // TODO Rolling Upgrade, hack, should only allow UPGRADED.
+    allowedStates.add(RepositoryVersionState.INSTALLED);
+    allowedStates.add(RepositoryVersionState.UPGRADING);
+    allowedStates.add(RepositoryVersionState.UPGRADED);
+
+    StringBuffer outSB = new StringBuffer();
+    StringBuffer errSB = new StringBuffer();
+
+    try {
+      String version = 
this.getExecutionCommand().getCommandParams().get("version");
+      String clusterName = this.getExecutionCommand().getClusterName();
+      outSB.append(MessageFormat.format("Begin finalizing the upgrade of 
cluster {0} to version {1}\n", clusterName, version));
+
+      Cluster cluster = clusters.getCluster(clusterName);
+
+      String stackId = cluster.getCurrentStackVersion().getStackId();
+      ClusterVersionEntity upgradingClusterVersion = 
clusterVersionDAO.findByClusterAndStackAndVersion(clusterName,
+          stackId, version);
+
+      if (upgradingClusterVersion == null) {
+        throw new AmbariException(String.format("Cluster stack version %s not 
found", version));
+      }
+
+      if (! allowedStates.contains(upgradingClusterVersion.getState())) {
+        throw new AmbariException(String.format("The cluster stack version 
state %s is not allowed to transition directly into %s",
+            upgradingClusterVersion.getState(), 
RepositoryVersionState.CURRENT.toString()));
+      }
+
+      // Validate that all of the hosts in the cluster have the version being 
upgraded to, and it is in an allowed state.
+      Map<String, Host> hosts = clusters.getHostsForCluster(clusterName);
+      List<HostVersionEntity> hostVersions = 
hostVersionDAO.findByClusterStackAndVersion(clusterName, stackId, version);
+
+      Set<String> hostWithAllowedVersion = new HashSet<String>();
+      for (HostVersionEntity hostVersion : hostVersions) {
+        if (allowedStates.contains(hostVersion.getState())) {
+          hostWithAllowedVersion.add(hostVersion.getHostName());
+        }
+      }
+
+      Set<String> hostsWithoutCorrectVersionState = new HashSet<String>();
+      for (String host : hosts.keySet()) {
+        if (!hostWithAllowedVersion.contains(host)) {
+          hostsWithoutCorrectVersionState.add(host);
+        }
+      }
+
+      if (hostsWithoutCorrectVersionState.size() > 0) {
+        throw new AmbariException(String.format("The following host(s) have 
not been upgraded to version %s. " +
+                "Please install and upgrade the Stack Version on those hosts 
and try again.",
+            version,
+            StringUtils.join(hostsWithoutCorrectVersionState, ", ")));
+      }
+
+      outSB.append(String.format("Will finalize the version for %d 
host(s).\n", hosts.keySet().size()));
+      cluster.mapHostVersions(hosts.keySet(), upgradingClusterVersion, 
RepositoryVersionState.CURRENT);
+
+      outSB.append(String.format("Will finalize the version for cluster 
%s.\n", clusterName));
+      cluster.transitionClusterVersion(stackId, version, 
RepositoryVersionState.CURRENT);
+
+      outSB.append("Upgrade was successful!\n");
+      return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", 
outSB.toString(), errSB.toString());
+    } catch (Exception e) {
+      errSB.append(e.getMessage());
+      return createCommandReport(-1, HostRoleStatus.FAILED, "{}", 
outSB.toString(), errSB.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
index a5d3ba2..d7bf2de 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java
@@ -119,7 +119,8 @@ public class UpgradeHelper {
               hostsType.hosts = order;
 
             } else {
-//              throw new AmbariException(MessageFormat.format("Could not find 
active and standby namenodes using hosts: {0}", 
StringUtils.join(hostsType.hosts, ", ").toString()));
+                // TODO Rolling Upgrade, enable once Namenode HA is a 
pre-check requirement.
+                // throw new AmbariException(MessageFormat.format("Could not 
find active and standby namenodes using hosts: {0}", 
StringUtils.join(hostsType.hosts, ", ").toString()));
             }
 
             builder.add(hostsType, service.serviceName, 
svc.isClientOnlyService(), pc);

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index a90fcc7..f80044e 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -1144,18 +1144,22 @@ public class ClusterImpl implements Cluster {
     try {
       readWriteLock.writeLock().lock();
       try {
-        Set<String> existingHostsWithClusterStackAndVersion = new 
HashSet<String>();
+        Map<String, HostVersionEntity> existingHostToHostVersionEntity = new 
HashMap<String, HostVersionEntity>();
         List<HostVersionEntity> existingHostVersionEntities = 
hostVersionDAO.findByClusterStackAndVersion(this.getClusterName(),
             currentClusterVersion.getRepositoryVersion().getStack(), 
currentClusterVersion.getRepositoryVersion().getVersion());
+
         if (existingHostVersionEntities != null) {
           for (HostVersionEntity entity : existingHostVersionEntities) {
-            existingHostsWithClusterStackAndVersion.add(entity.getHostName());
+            existingHostToHostVersionEntity.put(entity.getHostName(), entity);
           }
         }
 
-        Sets.SetView<String> intersection = 
Sets.intersection(existingHostsWithClusterStackAndVersion, hostNames);
+        Sets.SetView<String> intersection = 
Sets.intersection(existingHostToHostVersionEntity.keySet(), hostNames);
 
         for (String hostname : hostNames) {
+          List<HostVersionEntity> currentHostVersions = 
hostVersionDAO.findByClusterHostAndState(this.getClusterName(), hostname, 
RepositoryVersionState.CURRENT);
+          HostVersionEntity currentHostVersionEntity = (currentHostVersions != 
null &&  currentHostVersions.size() == 1) ? currentHostVersions.get(0) : null;
+
           // Notice that if any hosts already have the desired stack and 
version, regardless of the state, we try
           // to be robust and only insert records for the missing hosts.
           if (!intersection.contains(hostname)) {
@@ -1163,6 +1167,18 @@ public class ClusterImpl implements Cluster {
             HostVersionEntity hostVersionEntity = new 
HostVersionEntity(hostname, currentClusterVersion.getRepositoryVersion(), 
desiredState);
             hostVersionEntity.setHostEntity(hostEntity);
             hostVersionDAO.create(hostVersionEntity);
+          } else {
+            HostVersionEntity hostVersionEntity = 
existingHostToHostVersionEntity.get(hostname);
+            if (hostVersionEntity.getState() != desiredState) {
+              hostVersionEntity.setState(desiredState);
+              hostVersionDAO.merge(hostVersionEntity);
+            }
+
+            // Maintain the invariant that only one HostVersionEntity is 
allowed to have a state of CURRENT.
+            if (currentHostVersionEntity != null && 
!currentHostVersionEntity.getRepositoryVersion().equals(hostVersionEntity.getRepositoryVersion())
 && desiredState == RepositoryVersionState.CURRENT && 
currentHostVersionEntity.getState() == RepositoryVersionState.CURRENT) {
+              
currentHostVersionEntity.setState(RepositoryVersionState.INSTALLED);
+              hostVersionDAO.merge(currentHostVersionEntity);
+            }
           }
         }
       } finally {
@@ -1368,12 +1384,13 @@ public class ClusterImpl implements Cluster {
             case INSTALL_FAILED:
               allowedStates.add(RepositoryVersionState.INSTALLING);
             case INSTALLED:
-              allowedStates.add(RepositoryVersionState.INSTALLED);  // To 
allow reinstall
-              allowedStates.add(RepositoryVersionState.INSTALLING); // To 
allow reinstall
+              allowedStates.add(RepositoryVersionState.INSTALLING);
               allowedStates.add(RepositoryVersionState.UPGRADING);
             case UPGRADING:
-              allowedStates.add(RepositoryVersionState.CURRENT);
+              allowedStates.add(RepositoryVersionState.UPGRADED);
               allowedStates.add(RepositoryVersionState.UPGRADE_FAILED);
+            case UPGRADED:
+              allowedStates.add(RepositoryVersionState.CURRENT);
             case UPGRADE_FAILED:
               allowedStates.add(RepositoryVersionState.UPGRADING);
           }

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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 12e84e8..a9acafb 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
@@ -44,7 +44,9 @@ import 
org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 @XmlType(name="cluster")
 public class ClusterGrouping extends Grouping {
 
-
+  /**
+   * Stages against a Service and Component, or the Server
+   */
   @XmlElement(name="execute-stage")
   private List<ExecuteStage> executionStages;
 
@@ -61,9 +63,15 @@ public class ClusterGrouping extends Grouping {
     @XmlAttribute(name="title")
     public String title;
 
+    /**
+     * Optional service name, can be ""
+     */
     @XmlAttribute(name="service")
     public String service;
 
+    /**
+     * Optional component name, can be ""
+     */
     @XmlAttribute(name="component")
     public String component;
 
@@ -94,49 +102,52 @@ public class ClusterGrouping extends Grouping {
 
       List<StageWrapper> results = new ArrayList<StageWrapper>();
 
-      for (ExecuteStage execution : executionStages) {
-        Task task = execution.task;
+      if (executionStages != null) {
+        for (ExecuteStage execution : executionStages) {
+          Task task = execution.task;
 
-        StageWrapper wrapper = null;
+          StageWrapper wrapper = null;
 
-        if (null != execution.service && null != execution.component) {
+          if (null != execution.service && !execution.service.isEmpty() && 
null != execution.component && !execution.component.isEmpty()) {
 
-          HostsType hosts = m_resolver.getMasterAndHosts(execution.service, 
execution.component);
+            HostsType hosts = m_resolver.getMasterAndHosts(execution.service, 
execution.component);
 
-          if (null == hosts) {
-            continue;
-          }
+            if (null == hosts) {
+              continue;
+            }
 
-          Set<String> realHosts = new LinkedHashSet<String>(hosts.hosts);
+            Set<String> realHosts = new LinkedHashSet<String>(hosts.hosts);
 
-          // !!! FIXME other types
-          if (task.getType() == Task.Type.EXECUTE) {
-            ExecuteTask et = (ExecuteTask) task;
+            // !!! FIXME other types
+            if (task.getType() == Task.Type.EXECUTE) {
+              ExecuteTask et = (ExecuteTask) task;
 
-            if (null != et.hosts && "master".equals(et.hosts) && null != 
hosts.master) {
-              realHosts = Collections.singleton(hosts.master);
-            }
+              if (null != et.hosts && "master".equals(et.hosts) && null != 
hosts.master) {
+                realHosts = Collections.singleton(hosts.master);
+              }
 
-            wrapper = new StageWrapper(
-                StageWrapper.Type.RU_TASKS,
-                execution.title,
-                new TaskWrapper(execution.service, execution.component, 
realHosts, task));
-          }
-        } else {
-          switch (task.getType()) {
-            case MANUAL:
               wrapper = new StageWrapper(
-                  StageWrapper.Type.SERVER_SIDE_ACTION,
+                  StageWrapper.Type.RU_TASKS,
                   execution.title,
-                  new TaskWrapper(null, null, Collections.<String>emptySet(), 
task));
-              break;
-            default:
-              break;
+                  new TaskWrapper(execution.service, execution.component, 
realHosts, task));
+            }
+          } else {
+            switch (task.getType()) {
+              case MANUAL:
+              case SERVER_ACTION:
+                wrapper = new StageWrapper(
+                    StageWrapper.Type.SERVER_SIDE_ACTION,
+                    execution.title,
+                    new TaskWrapper(null, null, 
Collections.<String>emptySet(), task));
+                break;
+              default:
+                break;
+            }
           }
-        }
 
-        if (null != wrapper) {
-          results.add(wrapper);
+          if (null != wrapper) {
+            results.add(wrapper);
+          }
         }
       }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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 7fd58cd..076cac8 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
@@ -98,12 +98,12 @@ public class Grouping {
 
       buckets = buckets(pc.postTasks);
       for (TaskBucket bucket : buckets) {
-        List<TaskWrapper> preTasks = TaskWrapperBuilder.getTaskList(service, 
pc.name, hostsType, bucket.tasks);
-        Set<String> preTasksEffectiveHosts = 
TaskWrapperBuilder.getEffectiveHosts(preTasks);
+        List<TaskWrapper> postTasks = TaskWrapperBuilder.getTaskList(service, 
pc.name, hostsType, bucket.tasks);
+        Set<String> postTasksEffectiveHosts = 
TaskWrapperBuilder.getEffectiveHosts(postTasks);
         StageWrapper stage = new StageWrapper(
             bucket.type,
-            getStageText("Completing", pc.name, preTasksEffectiveHosts),
-            preTasks
+            getStageText("Completing", pc.name, postTasksEffectiveHosts),
+            postTasks
             );
         stages.add(stage);
       }
@@ -172,6 +172,7 @@ public class Grouping {
     private TaskBucket(Task initial) {
       switch (initial.getType()) {
         case CONFIGURE:
+        case SERVER_ACTION:
         case MANUAL:
           type = StageWrapper.Type.SERVER_SIDE_ACTION;
           break;
@@ -187,6 +188,5 @@ public class Grouping {
       }
       tasks.add(initial);
     }
-
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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
new file mode 100644
index 0000000..7a42c3b
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ServerActionTask.java
@@ -0,0 +1,44 @@
+/**
+ * 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.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction;
+
+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;
+
+/**
+ * Identifies that an upgrade step that requires confirmation before 
continuing.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="server_action")
+public class ServerActionTask extends ServerSideActionTask {
+
+  @XmlTransient
+  private Type type = Type.SERVER_ACTION;
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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 b98510b..97981ae 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,9 +27,7 @@ public abstract class ServerSideActionTask extends Task {
   @XmlAttribute(name="class")
   protected String implClass;
 
-
   public String getImplementationClass() {
     return implClass;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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 836bccb..f50cc7e 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
@@ -108,7 +108,4 @@ public class StageWrapper {
     RU_TASKS,
     SERVICE_CHECK
   }
-
-
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/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 f41aa68..fbd837c 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
@@ -23,7 +23,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})
+@XmlSeeAlso(value={ExecuteTask.class, ConfigureTask.class, ManualTask.class, 
RestartTask.class, ServerActionTask.class})
 public abstract class Task {
 
   /**
@@ -59,13 +59,17 @@ public abstract class Task {
     /**
      * Task that is a service check
      */
-    SERVICE_CHECK;
+    SERVICE_CHECK,
+    /**
+     * Task meant to run against Ambari server.
+     */
+    SERVER_ACTION;
 
     /**
      * @return {@code true} if the task is manual or automated.
      */
     public boolean isServerAction() {
-      return this == MANUAL || this == CONFIGURE;
+      return this == MANUAL || this == CONFIGURE || this == SERVER_ACTION;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml 
b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
index c02ffb8..dbb41e0 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/upgrades/upgrade-2.2.xml
@@ -21,6 +21,7 @@
   <target>2.2.*.*</target>
 
   <order>
+
     <group name="ZOOKEEPER" title="Zookeeper">
       <service name="ZOOKEEPER">
         <component>ZOOKEEPER_SERVER</component>
@@ -99,19 +100,23 @@
     </group>
 
     <group xsi:type="cluster" name="POST_CLUSTER" title="Finalize Upgrade">
-    <!--
+      <!--
       <execute-stage title="Confirm Finalize">
         <task xsi:type="manual">
           <message>Please confirm you are ready to finalize</message>
         </task>
       </execute-stage>
-    -->  
+      -->
       <execute-stage service="HDFS" component="NAMENODE" title="Execute HDFS 
Finalize">
         <task xsi:type="execute" hosts="master">
           <first>su - {{hadoop-env/hdfs_user}} -c 'hdfs dfsadmin 
-rollingUpgrade finalize'</first>
           <command>su - {{hadoop-env/hdfs_user}} -c 'hdfs dfsadmin -safemode 
leave'</command>
         </task>
       </execute-stage>
+      <execute-stage title="Save Cluster State" service="" component="">
+        <task xsi:type="server_action" 
class="org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction">
+        </task>
+      </execute-stage>
     </group>
    
   </order>
@@ -198,17 +203,6 @@
         <upgrade>
           <task xsi:type="restart" />
         </upgrade>
-
-        <!-- This step should be done once the user clicks on the "Finalize" 
button. So the name post-upgrade is misleading. -->
-        <post-upgrade>
-          <task xsi:type="execute" hosts="master">
-            <command>su - {{hadoop-env/hdfs_user}} -c 'hdfs dfsadmin 
-rollingUpgrade finalize'</command>
-          </task>
-          <task xsi:type="execute" hosts="master">
-            <first>su - {{hadoop-env/hdfs_user}} -c 'hdfs dfsadmin -safemode 
get | grep "Safe mode is ON in {{host_name}}"'</first>
-            <command>su - {{hadoop-env/hdfs_user}} -c 'hdfs dfsadmin -safemode 
leave'</command>
-          </task>
-        </post-upgrade>
       </component>
 
       <component name="DATANODE">

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
index cf5eea3..3266d9e 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
@@ -38,6 +38,7 @@ import org.apache.ambari.server.stack.HostsType;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
 import org.apache.ambari.server.state.stack.UpgradePack;
+import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
 import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Before;
@@ -99,7 +100,15 @@ public class UpgradeHelperTest {
     assertEquals("ZOOKEEPER", groups.get(1).name);
     assertEquals("CORE_MASTER", groups.get(2).name);
     assertEquals("CORE_SLAVES", groups.get(3).name);
-    assertEquals("POST_CLUSTER", groups.get(4).name);
+
+    UpgradeGroupHolder postGroup = groups.get(4);
+    assertEquals(postGroup.name, "POST_CLUSTER");
+    assertEquals(postGroup.title, "Finalize Upgrade");
+    assertEquals(postGroup.items.size(), 3);
+    assertEquals(postGroup.items.get(0).getText(), "Confirm Finalize");
+    assertEquals(postGroup.items.get(1).getText(), "Execute HDFS Finalize");
+    assertEquals(postGroup.items.get(2).getText(), "Save Cluster State");
+    assertEquals(postGroup.items.get(2).getType(), 
StageWrapper.Type.SERVER_SIDE_ACTION);
 
     assertEquals(6, groups.get(1).items.size());
     assertEquals(8, groups.get(2).items.size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
index 499b6c3..df6c8ac 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/UpgradePackTest.java
@@ -17,25 +17,14 @@
  */
 package org.apache.ambari.server.state.stack;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
-import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
-import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
-import org.apache.ambari.server.state.stack.upgrade.ExecuteTask;
-import org.apache.ambari.server.state.stack.upgrade.ManualTask;
-import org.apache.ambari.server.state.stack.upgrade.Task;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/ambari/blob/550563a1/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml 
b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
index 40eb7f3..c8da762 100644
--- 
a/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
+++ 
b/ambari-server/src/test/resources/stacks/HDP/2.1.1/upgrades/upgrade_test.xml
@@ -80,6 +80,10 @@
           <command>ls</command>
         </task>
       </execute-stage>
+      <execute-stage title="Save Cluster State" service="" component="">
+        <task xsi:type="server_action" 
class="org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction">
+        </task>
+      </execute-stage>
     </group>
         
   </order>

Reply via email to