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

ambari git commit: AMBARI-10976 - HDP-2.2 To HDP-2.3 Upgrade Pre-Upgrade Checks (jonathanhurley)

Repository: ambari
Updated Branches:
  refs/heads/trunk e65bad149 -> f4725228e


AMBARI-10976 - HDP-2.2 To HDP-2.3 Upgrade Pre-Upgrade Checks (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: f4725228e79416712986d0c2de1cb251c47e80b0
Parents: e65bad1
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed May 6 20:47:46 2015 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu May 7 08:12:02 2015 -0400

----------------------------------------------------------------------
 .../server/checks/AbstractCheckDescriptor.java  |  37 ++++-
 .../ambari/server/checks/CheckDescription.java  |  38 ++++-
 .../server/checks/ClientRetryPropertyCheck.java | 116 +++++++++++++
 .../server/checks/ConfigurationMergeCheck.java  |   3 +
 .../HiveDynamicServiceDiscoveryCheck.java       | 102 ++++++++++++
 .../server/checks/HostsHeartbeatCheck.java      |   4 +
 .../checks/HostsMasterMaintenanceCheck.java     |   4 +
 .../checks/HostsRepositoryVersionCheck.java     |   4 +
 .../checks/SecondaryNamenodeDeletedCheck.java   |   3 +
 .../checks/ServicesDecommissionCheck.java       |   3 +
 .../checks/ServicesMaintenanceModeCheck.java    |   4 +
 .../ServicesMapReduceDistributedCacheCheck.java |   4 +
 .../ServicesNamenodeHighAvailabilityCheck.java  |   4 +
 .../ServicesTezDistributedCacheCheck.java       |   4 +
 .../ambari/server/checks/ServicesUpCheck.java   |   4 +
 .../checks/ServicesYarnWorkPreservingCheck.java |  26 +--
 .../ambari/server/checks/UpgradeCheck.java      |  58 +++++++
 .../ambari/server/checks/UpgradeCheckGroup.java |  83 ++++++++++
 .../server/checks/UpgradeCheckRegistry.java     | 113 +++++++++++++
 .../checks/YarnRMHighAvailabilityCheck.java     |  80 +++++++++
 .../YarnTimelineServerStatePreservingCheck.java |  94 +++++++++++
 .../server/controller/ControllerModule.java     |  54 +++++-
 .../PreUpgradeCheckResourceProvider.java        |  74 +--------
 .../apache/ambari/server/state/CheckHelper.java |  31 ++--
 .../checks/ClientRetryPropertyCheckTest.java    | 164 +++++++++++++++++++
 .../server/checks/UpgradeCheckOrderTest.java    | 103 ++++++++++++
 ...nTimelineServerStatePreservingCheckTest.java | 127 ++++++++++++++
 .../ambari/server/state/CheckHelperTest.java    |  15 +-
 28 files changed, 1246 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
index 1816ce8..8cabf29 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
@@ -28,6 +28,8 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.PrereqCheckType;
@@ -46,8 +48,8 @@ import com.google.inject.Provider;
 public abstract class AbstractCheckDescriptor {
 
   private static final Logger LOG = LoggerFactory.getLogger(AbstractCheckDescriptor.class);
-  private static final StackId STACK_HDP_22 = new StackId("HDP", "2.2");
-  private static final StackId STACK_HDP_23 = new StackId("HDP", "2.3");
+  protected static final StackId STACK_HDP_22 = new StackId("HDP", "2.2");
+  protected static final StackId STACK_HDP_23 = new StackId("HDP", "2.3");
 
   protected static final String DEFAULT = "default";
 
@@ -178,6 +180,37 @@ public abstract class AbstractCheckDescriptor {
   }
 
   /**
+   * Gets a cluster configuration property if it exists, or {@code null}
+   * otherwise.
+   *
+   * @param request
+   *          the request (not {@code null}).
+   * @param configType
+   *          the configuration type, such as {@code hdfs-site} (not
+   *          {@code null}).
+   * @param propertyName
+   *          the name of the property (not {@code null}).
+   * @return the property value or {@code null} if not found.
+   * @throws AmbariException
+   */
+  protected String getProperty(PrereqCheckRequest request, String configType, String propertyName)
+      throws AmbariException {
+    final String clusterName = request.getClusterName();
+    final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+    final Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
+    final DesiredConfig desiredConfig = desiredConfigs.get(configType);
+
+    if (null == desiredConfig) {
+      return null;
+    }
+
+    final Config config = cluster.getConfig(configType, desiredConfig.getTag());
+
+    Map<String, String> properties = config.getProperties();
+    return properties.get(propertyName);
+  }
+
+  /**
    * Gets the fail reason
    * @param key               the failure text key
    * @param prerequisiteCheck the check being performed

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
index b00d6fb..7103566 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
@@ -28,6 +28,17 @@ import org.apache.ambari.server.state.stack.PrereqCheckType;
  */
 public enum CheckDescription {
 
+  CLIENT_RETRY(PrereqCheckType.SERVICE,
+      "Client Retry Properties",
+      new HashMap<String, String>() {{
+        put(ClientRetryPropertyCheck.HDFS_CLIENT_RETRY_MISSING_KEY,
+          "The hdfs-site.xml property dfs.client.retry.policy.enabled should be set to true.");
+        put(ClientRetryPropertyCheck.HIVE_CLIENT_RETRY_MISSING_KEY,
+          "The hive-site.xml property hive.metastore.failure.retries should be set to a positive value.");
+        put(ClientRetryPropertyCheck.OOZIE_CLIENT_RETRY_MISSING_KEY,
+          "The oozie-env.sh script must contain a retry count such as export OOZIE_CLIENT_OPTS=\"${OOZIE_CLIENT_OPTS} -Doozie.connection.retry.count=5\"");
+      }}),
+
   HOSTS_HEARTBEAT(PrereqCheckType.HOST,
       "All hosts must be heartbeating with the Ambari Server unless they are in Maintenance Mode",
       new HashMap<String, String>() {{
@@ -87,7 +98,7 @@ public enum CheckDescription {
       }}),
 
   SERVICES_NAMENODE_HA(PrereqCheckType.SERVICE,
-      "NameNode High Availability must  be enabled",
+      "NameNode High Availability must be enabled",
       new HashMap<String, String>() {{
         put(AbstractCheckDescriptor.DEFAULT,
           "NameNode High Availability is not enabled. Verify that dfs.nameservices property is present in hdfs-site.xml.");
@@ -123,6 +134,31 @@ public enum CheckDescription {
           "YARN should have work preserving restart enabled. The yarn-site.xml property yarn.resourcemanager.work-preserving-recovery.enabled property should be set to true.");
       }}),
 
+  SERVICES_YARN_RM_HA(PrereqCheckType.SERVICE,
+      "YARN ResourceManager HA should be enabled to prevent a disruption in service during the upgrade",
+      new HashMap<String, String>() {{
+        put(AbstractCheckDescriptor.DEFAULT,
+          "YARN ResourceManager High Availability is not enabled. Verify that dfs.nameservices property is present in hdfs-site.xml.");
+      }}),
+
+  SERVICES_YARN_TIMELINE_ST(PrereqCheckType.SERVICE,
+      "YARN Timeline state preserving restart should be enabled",
+      new HashMap<String, String>() {{
+        put(AbstractCheckDescriptor.DEFAULT,
+          "YARN should have state preserving restart enabled for the Timeline server. The yarn-site.xml property yarn.timeline-service.recovery.enabled should be set to true.");
+      }}),
+
+  SERVICES_HIVE_DYNAMIC_SERVICE_DISCOVERY(PrereqCheckType.SERVICE,
+      "Hive Dynamic Service Discovery",
+      new HashMap<String, String>() {{
+        put(HiveDynamicServiceDiscoveryCheck.HIVE_DYNAMIC_SERVICE_DISCOVERY_ENABLED_KEY,
+          "The hive-site.xml property hive.server2.support.dynamic.service.discovery should be set to true.");
+        put(HiveDynamicServiceDiscoveryCheck.HIVE_DYNAMIC_SERVICE_ZK_QUORUM_KEY,
+          "The hive-site.xml property hive.zookeeper.quorum should be set to a comma-separate list of ZooKeeper hosts:port pairs.");
+        put(HiveDynamicServiceDiscoveryCheck.HIVE_DYNAMIC_SERVICE_ZK_NAMESPACE_KEY,
+          "The hive-site.xml property hive.server2.zookeeper.namespace should be set to the value for the root namespace on ZooKeeper.");
+      }}),
+
   CONFIG_MERGE(PrereqCheckType.CLUSTER,
       "Configuration Merge Check",
       new HashMap<String, String>() {{

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ClientRetryPropertyCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ClientRetryPropertyCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ClientRetryPropertyCheck.java
new file mode 100644
index 0000000..5fbb5e4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ClientRetryPropertyCheck.java
@@ -0,0 +1,116 @@
+/*
+ * 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.checks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link ClientRetryPropertyCheck} class is used to check that the
+ * client retry properties for HDFS, HIVE, and OOZIE are set.
+ */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.CLIENT_RETRY_PROPERTY)
+public class ClientRetryPropertyCheck extends AbstractCheckDescriptor {
+
+  static final String HDFS_CLIENT_RETRY_MISSING_KEY = "hdfs.client.retry.missing.key";
+  static final String HIVE_CLIENT_RETRY_MISSING_KEY = "hive.client.retry.missing.key";
+  static final String OOZIE_CLIENT_RETRY_MISSING_KEY = "oozie.client.retry.missing.key";
+
+  /**
+   * Constructor.
+   */
+  public ClientRetryPropertyCheck() {
+    super(CheckDescription.CLIENT_RETRY);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
+    final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+    Map<String, Service> services = cluster.getServices();
+
+    if (services.containsKey("HDFS") || services.containsKey("HIVE")
+        || services.containsKey("OOZIE")) {
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+    final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+    Map<String, Service> services = cluster.getServices();
+
+    List<String> errorMessages = new ArrayList<String>();
+
+    // check hdfs client property
+    if (services.containsKey("HDFS")) {
+      String hdfsClientRetry = getProperty(request, "hdfs-site", "dfs.client.retry.policy.enabled");
+      if (null == hdfsClientRetry || !Boolean.parseBoolean(hdfsClientRetry)) {
+        errorMessages.add(getFailReason(HDFS_CLIENT_RETRY_MISSING_KEY, prerequisiteCheck, request));
+        prerequisiteCheck.getFailedOn().add("HDFS");
+      }
+    }
+
+    // check hive client properties
+    if (services.containsKey("HIVE")) {
+      String hiveClientRetryCount = getProperty(request, "hive-site",
+          "hive.metastore.failure.retries");
+
+      if (null != hiveClientRetryCount && Integer.parseInt(hiveClientRetryCount) <= 0) {
+        errorMessages.add(getFailReason(HIVE_CLIENT_RETRY_MISSING_KEY, prerequisiteCheck, request));
+        prerequisiteCheck.getFailedOn().add("HIVE");
+      }
+    }
+
+    if (services.containsKey("OOZIE")) {
+      String oozieClientRetry = getProperty(request, "oozie-env", "template");
+      if (null == oozieClientRetry || !oozieClientRetry.contains("-Doozie.connection.retry.count")) {
+        errorMessages.add(getFailReason(OOZIE_CLIENT_RETRY_MISSING_KEY, prerequisiteCheck, request));
+        prerequisiteCheck.getFailedOn().add("OOZIE");
+      }
+    }
+
+    if (!errorMessages.isEmpty()) {
+      prerequisiteCheck.setFailReason(StringUtils.join(errorMessages, " "));
+      prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java
index e4dd0e6..095ecd5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java
@@ -33,10 +33,13 @@ import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Checks for configuration merge conflicts.
  */
+@Singleton
+@UpgradeCheck(order = 99.0f)
 public class ConfigurationMergeCheck extends AbstractCheckDescriptor {
 
   @Inject

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/HiveDynamicServiceDiscoveryCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HiveDynamicServiceDiscoveryCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HiveDynamicServiceDiscoveryCheck.java
new file mode 100644
index 0000000..74bed8a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HiveDynamicServiceDiscoveryCheck.java
@@ -0,0 +1,102 @@
+/*
+ * 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.checks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link HiveDynamicServiceDiscoveryCheck} class is used to check that HIVE
+ * is properly configured for dynamic discovery.
+ */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.DEFAULT, order = 1.0f)
+public class HiveDynamicServiceDiscoveryCheck extends AbstractCheckDescriptor {
+
+  static final String HIVE_DYNAMIC_SERVICE_DISCOVERY_ENABLED_KEY = "hive.dynamic-service.discovery.enabled.key";
+  static final String HIVE_DYNAMIC_SERVICE_ZK_QUORUM_KEY = "hive.dynamic-service.discovery.zk-quorum.key";
+  static final String HIVE_DYNAMIC_SERVICE_ZK_NAMESPACE_KEY = "hive.dynamic-service.zk-namespace.key";
+
+  /**
+   * Constructor.
+   */
+  public HiveDynamicServiceDiscoveryCheck() {
+    super(CheckDescription.SERVICES_HIVE_DYNAMIC_SERVICE_DISCOVERY);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
+    final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+    Map<String, Service> services = cluster.getServices();
+    if (services.containsKey("HIVE")) {
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+    List<String> errorMessages = new ArrayList<String>();
+
+    String dynamicServiceDiscoveryEnabled = getProperty(request, "hive-site", "hive.server2.support.dynamic.service.discovery");
+    String zookeeperQuorum = getProperty(request, "hive-site", "hive.zookeeper.quorum");
+    String zookeeperNamespace = getProperty(request, "hive-site", "hive.server2.zookeeper.namespace");
+
+    if (null == dynamicServiceDiscoveryEnabled || !Boolean.parseBoolean(dynamicServiceDiscoveryEnabled)) {
+      errorMessages.add(getFailReason(HIVE_DYNAMIC_SERVICE_DISCOVERY_ENABLED_KEY, prerequisiteCheck, request));
+    }
+
+    if (StringUtils.isBlank(zookeeperQuorum)) {
+      errorMessages.add(getFailReason(HIVE_DYNAMIC_SERVICE_ZK_QUORUM_KEY, prerequisiteCheck,
+          request));
+    }
+
+    if (StringUtils.isBlank(zookeeperNamespace)) {
+      errorMessages.add(getFailReason(HIVE_DYNAMIC_SERVICE_ZK_NAMESPACE_KEY, prerequisiteCheck,
+          request));
+    }
+
+    if (!errorMessages.isEmpty()) {
+      prerequisiteCheck.setFailReason(StringUtils.join(errorMessages, " "));
+      prerequisiteCheck.getFailedOn().add("HIVE");
+      prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsHeartbeatCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsHeartbeatCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsHeartbeatCheck.java
index cf9e4ae..6076a32 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsHeartbeatCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsHeartbeatCheck.java
@@ -28,9 +28,13 @@ import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that all hosts are either in maintenance mode or heartbeating with the server.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.LIVELINESS, order = 1.0f)
 public class HostsHeartbeatCheck extends AbstractCheckDescriptor {
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java
index 2c5ff28..ef93337 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java
@@ -34,9 +34,13 @@ import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that all hosts in maintenance state do not have master components.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.MAINTENANCE_MODE, order = 1.0f)
 public class HostsMasterMaintenanceCheck extends AbstractCheckDescriptor {
 
   static final String KEY_NO_UPGRADE_NAME = "no_upgrade_name";

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java
index 0ea5d08..6ebf8e1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java
@@ -32,9 +32,13 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that all hosts have particular repository version.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.REPOSITORY_VERSION)
 public class HostsRepositoryVersionCheck extends AbstractCheckDescriptor {
 
   static final String KEY_NO_REPO_VERSION = "no_repo_version";

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java
index 14ec2c1..493042f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java
@@ -34,10 +34,13 @@ import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * Checks that the Secondary NameNode is not present on any of the hosts.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.NAMENODE_HA, order = 2.0f)
 public class SecondaryNamenodeDeletedCheck extends AbstractCheckDescriptor {
   @Inject
   HostComponentStateDAO hostComponentStateDao;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesDecommissionCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesDecommissionCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesDecommissionCheck.java
index 7497c2f..6ebfd1f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesDecommissionCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesDecommissionCheck.java
@@ -29,9 +29,12 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that there are no services in decommission state.
  */
+@Singleton
 public class ServicesDecommissionCheck extends AbstractCheckDescriptor {
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheck.java
index 0ae5c46..2b5ff49 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheck.java
@@ -28,9 +28,13 @@ import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that services are in the maintenance mode.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.MAINTENANCE_MODE, order = 2.0f)
 public class ServicesMaintenanceModeCheck extends AbstractCheckDescriptor {
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java
index 36526e3..be5d11a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java
@@ -31,9 +31,13 @@ import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.commons.lang.StringUtils;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that MR jobs reference hadoop libraries from the distributed cache.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.NAMENODE_HA, order = 3.0f)
 public class ServicesMapReduceDistributedCacheCheck extends AbstractCheckDescriptor {
 
   static final String KEY_APP_CLASSPATH = "app_classpath";

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java
index e43e4fb..d92f12d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java
@@ -28,9 +28,13 @@ import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that namenode high availability is enabled.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.NAMENODE_HA, order = 1.0f)
 public class ServicesNamenodeHighAvailabilityCheck extends AbstractCheckDescriptor {
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java
index 41735b4..68a7103 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java
@@ -31,9 +31,13 @@ import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.commons.lang.StringUtils;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that Tez jobs reference hadoop libraries from the distributed cache.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.NAMENODE_HA, order = 4.0f)
 public class ServicesTezDistributedCacheCheck extends AbstractCheckDescriptor {
 
   static final String KEY_LIB_URI_MISSING = "tez_lib_uri_missing";

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java
index e0696fa..243b26d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java
@@ -27,9 +27,13 @@ import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that services are up.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.LIVELINESS, order = 2.0f)
 public class ServicesUpCheck extends AbstractCheckDescriptor {
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java
index a56f35d..a0b2b59 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java
@@ -17,21 +17,21 @@
  */
 package org.apache.ambari.server.checks;
 
-import java.util.Map;
-
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.controller.PrereqCheckRequest;
 import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.commons.lang.BooleanUtils;
 
+import com.google.inject.Singleton;
+
 /**
  * Checks that YARN has work-preserving restart enabled.
  */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.DEFAULT, order = 1.0f)
 public class ServicesYarnWorkPreservingCheck extends AbstractCheckDescriptor {
 
   /**
@@ -41,6 +41,9 @@ public class ServicesYarnWorkPreservingCheck extends AbstractCheckDescriptor {
     super(CheckDescription.SERVICES_YARN_WP);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
     if (!super.isApplicable(request)) {
@@ -56,16 +59,15 @@ public class ServicesYarnWorkPreservingCheck extends AbstractCheckDescriptor {
     return true;
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
-    final String clusterName = request.getClusterName();
-    final Cluster cluster = clustersProvider.get().getCluster(clusterName);
-    final String configType = "yarn-site";
-    final Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
-    final DesiredConfig desiredConfig = desiredConfigs.get(configType);
-    final Config config = cluster.getConfig(configType, desiredConfig.getTag());
-    if (!config.getProperties().containsKey("yarn.resourcemanager.work-preserving-recovery.enabled") ||
-      !BooleanUtils.toBoolean(config.getProperties().get("yarn.resourcemanager.work-preserving-recovery.enabled"))) {
+    String propertyValue = getProperty(request, "yarn-site",
+        "yarn.resourcemanager.work-preserving-recovery.enabled");
+
+    if (null == propertyValue || !BooleanUtils.toBoolean(propertyValue)) {
       prerequisiteCheck.getFailedOn().add("YARN");
       prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
       prerequisiteCheck.setFailReason(getFailReason(prerequisiteCheck, request));

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
new file mode 100644
index 0000000..9fa8916
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheck.java
@@ -0,0 +1,58 @@
+/**
+ * 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.checks;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import com.google.inject.ScopeAnnotation;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link UpgradeCheck} annotation is used to provide ordering and grouping
+ * to any {@link AbstractCheckDescriptor} instance.
+ * <p/>
+ * Classes marked with this annotation should also be {@link Singleton}. They
+ * will be discovered on the classpath and then registered with the
+ * {@link UpgradeCheckRegistry}.
+ */
+@Target({ ElementType.TYPE })
+@Retention(RUNTIME)
+@ScopeAnnotation
+public @interface UpgradeCheck {
+
+  /**
+   * The group that the pre-upgrade check belongs to.
+   *
+   * @return the group, or {@link UpgradeCheckGroup#DEFAULT} if not specified.
+   */
+  UpgradeCheckGroup group() default UpgradeCheckGroup.DEFAULT;
+
+  /**
+   * The order of the pre-upgrade check within its group.
+   * <p/>
+   * The order is determined by a {@code float} so that new checks can be added
+   * in between others without the need to reorder all of the existing checks.
+   *
+   * @return the order, or {@code 1.0f} if not specified.
+   */
+  float order() default 1.0f;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckGroup.java
new file mode 100644
index 0000000..16e56f3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckGroup.java
@@ -0,0 +1,83 @@
+/**
+ * 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.checks;
+
+/**
+ * The {@link UpgradeCheckGroup} enum is used to organize pre-upgrade checks
+ * into specific groups that have their own relational ordering.
+ * <p/>
+ * The order for each group is determined by a {@code float} so that new groups
+ * can be added in between others without the need to reorder all of the groups.
+ */
+public enum UpgradeCheckGroup {
+
+  /**
+   * Check for masters in maintenance mode and then services in maintenance
+   * mode.
+   */
+  MAINTENANCE_MODE(1.0f),
+
+  /**
+   * Checks the repository version on the hosts.
+   */
+  REPOSITORY_VERSION(2.0f),
+
+  /**
+   * Checks for NameNode HA and checks that depend on NameNode HA.
+   */
+  NAMENODE_HA(3.0f),
+
+  /**
+   * Checks for the state of a host or service being alive and responsive.
+   */
+  LIVELINESS(4.0f),
+
+  /**
+   * Checks for the client retry properties to be set in clients that support
+   * this.
+   */
+  CLIENT_RETRY_PROPERTY(5.0f),
+
+  /**
+   * All other checks.
+   */
+  DEFAULT(Float.MAX_VALUE);
+
+  /**
+   * The order of upgrade check groups.
+   */
+  private final Float m_order;
+
+  /**
+   * Constructor.
+   *
+   * @param order
+   */
+  private UpgradeCheckGroup(Float order) {
+    m_order = order;
+  }
+
+  /**
+   * Gets the group's order.
+   *
+   * @return the order of the group.
+   */
+  public Float getOrder() {
+    return m_order;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckRegistry.java
new file mode 100644
index 0000000..8be572c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/UpgradeCheckRegistry.java
@@ -0,0 +1,113 @@
+/**
+ * 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.checks;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link UpgradeCheckRegistry} contains the ordered list of all pre-upgrade
+ * checks. This will order the checks according to
+ * {@link PreUpgradeCheckComparator}.
+ */
+@Singleton
+public class UpgradeCheckRegistry {
+
+  /**
+   * The list of upgrade checks to run through.
+   */
+  private Set<AbstractCheckDescriptor> m_upgradeChecks = new TreeSet<AbstractCheckDescriptor>(
+      new PreUpgradeCheckComparator());
+
+  /**
+   * Register an upgrade check.
+   *
+   * @param upgradeCheck
+   *          the check to register (not {@code null}).
+   */
+  public void register(AbstractCheckDescriptor upgradeCheck) {
+    m_upgradeChecks.add(upgradeCheck);
+  }
+
+  /**
+   * Gets an ordered list of all of the upgrade checks.
+   *
+   * @return
+   */
+  public List<AbstractCheckDescriptor> getUpgradeChecks() {
+    return new ArrayList<AbstractCheckDescriptor>(m_upgradeChecks);
+  }
+
+  /**
+   * THe {@link PreUpgradeCheckComparator} class is used to compare
+   * {@link AbstractCheckDescriptor} based on their {@link UpgradeCheck}
+   * annotations.
+   */
+  private static final class PreUpgradeCheckComparator implements
+      Comparator<AbstractCheckDescriptor> {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compare(AbstractCheckDescriptor check1, AbstractCheckDescriptor check2) {
+      Class<? extends AbstractCheckDescriptor> clazz1 = check1.getClass();
+      Class<? extends AbstractCheckDescriptor> clazz2 = check2.getClass();
+
+      UpgradeCheck annotation1 = clazz1.getAnnotation(UpgradeCheck.class);
+      UpgradeCheck annotation2 = clazz2.getAnnotation(UpgradeCheck.class);
+
+      UpgradeCheckGroup group1 = UpgradeCheckGroup.DEFAULT;
+      UpgradeCheckGroup group2 = UpgradeCheckGroup.DEFAULT;
+      Float groupOrder1 = Float.valueOf(group1.getOrder());
+      Float groupOrder2 = Float.valueOf(group2.getOrder());
+
+      Float order1 = 1.0f;
+      Float order2 = 1.0f;
+
+      if (null != annotation1) {
+        group1 = annotation1.group();
+        groupOrder1 = Float.valueOf(group1.getOrder());
+        order1 = Float.valueOf(annotation1.order());
+      }
+
+      if (null != annotation2) {
+        group2 = annotation2.group();
+        groupOrder2 = Float.valueOf(group2.getOrder());
+        order2 = Float.valueOf(annotation2.order());
+      }
+
+      int groupComparison = groupOrder1.compareTo(groupOrder2);
+      if (groupComparison != 0) {
+        return groupComparison;
+      }
+
+      int orderComparison = order1.compareTo(order2);
+      if (orderComparison != 0) {
+        return orderComparison;
+      }
+
+      return clazz1.getName().compareTo(clazz2.getName());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnRMHighAvailabilityCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnRMHighAvailabilityCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnRMHighAvailabilityCheck.java
new file mode 100644
index 0000000..db8af29
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnRMHighAvailabilityCheck.java
@@ -0,0 +1,80 @@
+/*
+ * 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.checks;
+
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.commons.lang.BooleanUtils;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link YarnRMHighAvailabilityCheck} checks that YARN has HA mode enabled
+ * for ResourceManager..
+ */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.DEFAULT, order = 1.0f)
+public class YarnRMHighAvailabilityCheck extends AbstractCheckDescriptor {
+
+  /**
+   * Constructor.
+   */
+  public YarnRMHighAvailabilityCheck() {
+    super(CheckDescription.SERVICES_YARN_RM_HA);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
+    final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+    Map<String, Service> services = cluster.getServices();
+    if (!services.containsKey("YARN")) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+    // pretty weak sauce here; probably should do a bit more, like query JMX to
+    // see that there is at least 1 RM active and 1 in standby
+    String propertyValue = getProperty(request, "yarn-site", "yarn.resourcemanager.ha.enabled");
+
+    if (null == propertyValue || !BooleanUtils.toBoolean(propertyValue)) {
+      prerequisiteCheck.getFailedOn().add("YARN");
+      prerequisiteCheck.setStatus(PrereqCheckStatus.WARNING);
+      prerequisiteCheck.setFailReason(getFailReason(prerequisiteCheck, request));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheck.java
new file mode 100644
index 0000000..ef7cbff
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheck.java
@@ -0,0 +1,94 @@
+/*
+ * 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.checks;
+
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.ambari.server.utils.VersionUtils;
+import org.apache.commons.lang.BooleanUtils;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link YarnTimelineServerStatePreservingCheck} is used to check that the
+ * YARN Timeline server has state preserving mode enabled. This value is only
+ * present in HDP 2.2.4.2+.
+ */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.DEFAULT, order = 1.0f)
+public class YarnTimelineServerStatePreservingCheck extends AbstractCheckDescriptor {
+
+  private final static String YARN_TIMELINE_STATE_RECOVERY_ENABLED_KEY = "yarn.timeline-service.recovery.enabled";
+
+  /**
+   * Constructor.
+   */
+  public YarnTimelineServerStatePreservingCheck() {
+    super(CheckDescription.SERVICES_YARN_TIMELINE_ST);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
+    final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+    Map<String, Service> services = cluster.getServices();
+    if (!services.containsKey("YARN")) {
+      return false;
+    }
+
+    // not applicable if not HDP 2.2.4.2 or later
+    String stackName = cluster.getCurrentStackVersion().getStackName();
+    if (!"HDP".equals(stackName)) {
+      return false;
+    }
+
+    String currentClusterRepositoryVersion = cluster.getCurrentClusterVersion().getRepositoryVersion().getVersion();
+    if (VersionUtils.compareVersions(currentClusterRepositoryVersion, "2.2.4.2") < 0) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+    String propertyValue = getProperty(request, "yarn-site",
+        YARN_TIMELINE_STATE_RECOVERY_ENABLED_KEY);
+
+    if (null == propertyValue || !BooleanUtils.toBoolean(propertyValue)) {
+      prerequisiteCheck.getFailedOn().add("YARN");
+      prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+      prerequisiteCheck.setFailReason(getFailReason(prerequisiteCheck, request));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 08a56d0..432e41a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -56,6 +56,8 @@ import org.apache.ambari.server.actionmanager.HostRoleCommandFactoryImpl;
 import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.actionmanager.StageFactoryImpl;
+import org.apache.ambari.server.checks.AbstractCheckDescriptor;
+import org.apache.ambari.server.checks.UpgradeCheckRegistry;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.configuration.Configuration.ConnectionPoolType;
 import org.apache.ambari.server.configuration.Configuration.DatabaseType;
@@ -144,6 +146,7 @@ import com.mchange.v2.c3p0.ComboPooledDataSource;
  */
 public class ControllerModule extends AbstractModule {
   private static Logger LOG = LoggerFactory.getLogger(ControllerModule.class);
+  private static final String AMBARI_PACKAGE = "org.apache.ambari.server";
 
   private final Configuration configuration;
   private final OsFamily os_family;
@@ -329,6 +332,7 @@ public class ControllerModule extends AbstractModule {
 
     bindByAnnotation(null);
     bindNotificationDispatchers();
+    registerUpgradeChecks();
   }
 
 
@@ -451,7 +455,7 @@ public class ControllerModule extends AbstractModule {
         scanner.addIncludeFilter(new AnnotationTypeFilter(cls));
       }
 
-      beanDefinitions = scanner.findCandidateComponents("org.apache.ambari.server");
+      beanDefinitions = scanner.findCandidateComponents(AMBARI_PACKAGE);
     }
 
     if (null == beanDefinitions || beanDefinitions.size() == 0) {
@@ -557,4 +561,52 @@ public class ControllerModule extends AbstractModule {
       }
     }
   }
+
+  /**
+   * Searches for all instances of {@link AbstractCheckDescriptor} on the
+   * classpath and registers each as a singleton with the
+   * {@link UpgradeCheckRegistry}.
+   */
+  @SuppressWarnings("unchecked")
+  private void registerUpgradeChecks() {
+    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
+        false);
+
+    // make the registry a singleton
+    UpgradeCheckRegistry registry = new UpgradeCheckRegistry();
+    bind(UpgradeCheckRegistry.class).toInstance(registry);
+
+    // match all implementations of the base check class
+    AssignableTypeFilter filter = new AssignableTypeFilter(AbstractCheckDescriptor.class);
+    scanner.addIncludeFilter(filter);
+
+    Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(AMBARI_PACKAGE);
+
+    // no dispatchers is a problem
+    if (null == beanDefinitions || beanDefinitions.size() == 0) {
+      LOG.error("No instances of {} found to register", AbstractCheckDescriptor.class);
+      return;
+    }
+
+    // for every discovered check, singleton-ize them and register with the
+    // registry
+    for (BeanDefinition beanDefinition : beanDefinitions) {
+      String className = beanDefinition.getBeanClassName();
+      Class<?> clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
+
+      try {
+        AbstractCheckDescriptor upgradeCheck = (AbstractCheckDescriptor) clazz.newInstance();
+        bind((Class<AbstractCheckDescriptor>) clazz).toInstance(upgradeCheck);
+        registry.register(upgradeCheck);
+      } catch (Exception exception) {
+        LOG.error("Unable to bind and register upgrade check {}", clazz, exception);
+      }
+    }
+
+    // log the order of the pre-upgrade checks
+    List<AbstractCheckDescriptor> upgradeChecks = registry.getUpgradeChecks();
+    for (AbstractCheckDescriptor upgradeCheck : upgradeChecks) {
+      LOG.error("Registered pre-upgrade check {}", upgradeCheck.getClass());
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
index 3460423..207bf89 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
@@ -17,29 +17,15 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StaticallyInject;
-import org.apache.ambari.server.checks.AbstractCheckDescriptor;
-import org.apache.ambari.server.checks.ConfigurationMergeCheck;
-import org.apache.ambari.server.checks.HostsHeartbeatCheck;
-import org.apache.ambari.server.checks.HostsMasterMaintenanceCheck;
-import org.apache.ambari.server.checks.HostsRepositoryVersionCheck;
-import org.apache.ambari.server.checks.SecondaryNamenodeDeletedCheck;
-import org.apache.ambari.server.checks.ServicesDecommissionCheck;
-import org.apache.ambari.server.checks.ServicesMaintenanceModeCheck;
-import org.apache.ambari.server.checks.ServicesMapReduceDistributedCacheCheck;
-import org.apache.ambari.server.checks.ServicesNamenodeHighAvailabilityCheck;
-import org.apache.ambari.server.checks.ServicesTezDistributedCacheCheck;
-import org.apache.ambari.server.checks.ServicesUpCheck;
-import org.apache.ambari.server.checks.ServicesYarnWorkPreservingCheck;
+import org.apache.ambari.server.checks.UpgradeCheckRegistry;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.PrereqCheckRequest;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
@@ -80,65 +66,13 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
   public static final String UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "repository_version");
 
   @Inject
-  private static ServicesMaintenanceModeCheck servicesMaintenanceModeCheck;
-
-  @Inject
-  private static HostsMasterMaintenanceCheck hostsMasterMaintenanceCheck;
-
-  @Inject
-  private static HostsRepositoryVersionCheck hostsRepositoryVersionCheck;
-
-  @Inject
-  private static ServicesNamenodeHighAvailabilityCheck servicesNamenodeHighAvailabilityCheck;
-
-  @Inject
-  private static SecondaryNamenodeDeletedCheck secondaryNamenodeDeletedCheck;
-
-  @Inject
-  private static ServicesYarnWorkPreservingCheck servicesYarnWorkPreservingCheck;
-
-  @Inject
-  private static ServicesDecommissionCheck servicesDecommissionCheck;
-
-  @Inject
-  private static ServicesMapReduceDistributedCacheCheck servicesJobsDistributedCacheCheck;
-
-  @Inject
-  private static HostsHeartbeatCheck heartbeatCheck;
-
-  @Inject
-  private static ServicesUpCheck servicesUpCheck;
-
-  @Inject
-  private static ServicesTezDistributedCacheCheck servicesTezDistributedCacheCheck;
-
-  @Inject
-  private static ConfigurationMergeCheck configMergeCheck;
-
-  @Inject
   private static Provider<Clusters> clustersProvider;
 
   @Inject
   private static RepositoryVersionDAO repositoryVersionDAO;
 
-  /**
-   * List of the registered upgrade checks.  Make sure that if a check that
-   * depends on the result of another check comes earlier in the list.
-   * For example, MR2 and Tez distributed cache checks rely on NN-HA check passing.
-   */
-  private List<AbstractCheckDescriptor> updateChecksRegistry = Arrays.asList(
-      hostsMasterMaintenanceCheck,
-      hostsRepositoryVersionCheck,
-      servicesMaintenanceModeCheck,
-      servicesNamenodeHighAvailabilityCheck,
-      secondaryNamenodeDeletedCheck,
-      servicesYarnWorkPreservingCheck,
-      servicesDecommissionCheck,
-      servicesJobsDistributedCacheCheck,
-      heartbeatCheck,
-      servicesUpCheck,
-      servicesTezDistributedCacheCheck,
-      configMergeCheck);
+  @Inject
+  private static UpgradeCheckRegistry upgradeCheckRegistry;
 
   private static Set<String> pkPropertyIds = Collections.singleton(UPGRADE_CHECK_ID_PROPERTY_ID);
 
@@ -203,7 +137,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
         upgradeCheckRequest.setTargetStackId(repositoryVersionEntity.getStackId());
       }
 
-      for (PrerequisiteCheck prerequisiteCheck : checkHelper.performChecks(upgradeCheckRequest, updateChecksRegistry)) {
+      for (PrerequisiteCheck prerequisiteCheck : checkHelper.performChecks(upgradeCheckRequest, upgradeCheckRegistry.getUpgradeChecks())) {
         final Resource resource = new ResourceImpl(Resource.Type.PreUpgradeCheck);
         setResourceProperty(resource, UPGRADE_CHECK_ID_PROPERTY_ID, prerequisiteCheck.getId(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_CHECK_PROPERTY_ID, prerequisiteCheck.getDescription(), requestedIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/main/java/org/apache/ambari/server/state/CheckHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/CheckHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/CheckHelper.java
index abaf8e7..5a8d4fd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/CheckHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/CheckHelper.java
@@ -37,27 +37,31 @@ public class CheckHelper {
    */
   private static Logger LOG = LoggerFactory.getLogger(CheckHelper.class);
 
-
   /**
    * Executes all registered pre-requisite checks.
    *
-   * @param request pre-requisite check request
+   * @param request
+   *          pre-requisite check request
    * @return list of pre-requisite check results
    */
-  public List<PrerequisiteCheck> performChecks(PrereqCheckRequest request, List<AbstractCheckDescriptor> checksRegistry) {
+  public List<PrerequisiteCheck> performChecks(PrereqCheckRequest request,
+      List<AbstractCheckDescriptor> checksRegistry) {
 
     final String clusterName = request.getClusterName();
     final List<PrerequisiteCheck> prerequisiteCheckResults = new ArrayList<PrerequisiteCheck>();
     for (AbstractCheckDescriptor checkDescriptor : checksRegistry) {
       final PrerequisiteCheck prerequisiteCheck = new PrerequisiteCheck(
           checkDescriptor.getDescription(), clusterName);
-      try {
-        if (checkDescriptor.isApplicable(request)) {
-          checkDescriptor.perform(prerequisiteCheck, request);
-          prerequisiteCheckResults.add(prerequisiteCheck);
 
-          request.addResult(checkDescriptor.getDescription(), prerequisiteCheck.getStatus());
+      try {
+        if (!checkDescriptor.isApplicable(request)) {
+          continue;
         }
+
+        checkDescriptor.perform(prerequisiteCheck, request);
+        prerequisiteCheckResults.add(prerequisiteCheck);
+
+        request.addResult(checkDescriptor.getDescription(), prerequisiteCheck.getStatus());
       } catch (ClusterNotFoundException ex) {
         prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
         prerequisiteCheck.setFailReason("Cluster with name " + clusterName + " doesn't exists");
@@ -72,19 +76,8 @@ public class CheckHelper {
 
         request.addResult(checkDescriptor.getDescription(), prerequisiteCheck.getStatus());
       }
-
-
-
-
-
-
-
-
-
-
     }
 
-
     return prerequisiteCheckResults;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/test/java/org/apache/ambari/server/checks/ClientRetryPropertyCheckTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/ClientRetryPropertyCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/ClientRetryPropertyCheckTest.java
new file mode 100644
index 0000000..92b6a85
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/ClientRetryPropertyCheckTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.checks;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.google.inject.Provider;
+
+/**
+ * Tests for {@link ClientRetryPropertyCheckTest}
+ */
+public class ClientRetryPropertyCheckTest {
+  private final Clusters m_clusters = Mockito.mock(Clusters.class);
+
+  private final ClientRetryPropertyCheck m_check = new ClientRetryPropertyCheck();
+
+  /**
+   *
+   */
+  @Before
+  public void setup() {
+    m_check.clustersProvider = new Provider<Clusters>() {
+
+      @Override
+      public Clusters get() {
+        return m_clusters;
+      }
+    };
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testIsApplicable() throws Exception {
+    final Cluster cluster = Mockito.mock(Cluster.class);
+    Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(m_clusters.getCluster("cluster")).thenReturn(cluster);
+
+    Map<String, Service> services = new HashMap<String, Service>();
+    Mockito.when(cluster.getServices()).thenReturn(services);
+
+    PrereqCheckRequest request = new PrereqCheckRequest("cluster");
+    request.setRepositoryVersion("2.3.0.0");
+
+    // nothing installed
+    Assert.assertFalse(m_check.isApplicable(request));
+
+    // YARN installed
+    services.put("HDFS", Mockito.mock(Service.class));
+    Assert.assertTrue(m_check.isApplicable(request));
+
+    // OOZIE installed
+    services.clear();
+    services.put("OOZIE", Mockito.mock(Service.class));
+    Assert.assertTrue(m_check.isApplicable(request));
+  }
+
+  @Test
+  public void testPerform() throws Exception {
+    final Cluster cluster = Mockito.mock(Cluster.class);
+
+    Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(m_clusters.getCluster("cluster")).thenReturn(cluster);
+    Map<String, Service> services = new HashMap<String, Service>();
+    Mockito.when(cluster.getServices()).thenReturn(services);
+
+    services.put("HDFS", Mockito.mock(Service.class));
+
+    final DesiredConfig desiredConfig = Mockito.mock(DesiredConfig.class);
+    Mockito.when(desiredConfig.getTag()).thenReturn("tag");
+    Map<String, DesiredConfig> configMap = new HashMap<String, DesiredConfig>();
+    configMap.put("hdfs-site", desiredConfig);
+    configMap.put("hive-site", desiredConfig);
+    configMap.put("oozie-env", desiredConfig);
+
+    Mockito.when(cluster.getDesiredConfigs()).thenReturn(configMap);
+    final Config config = Mockito.mock(Config.class);
+    Mockito.when(cluster.getConfig(Mockito.anyString(), Mockito.anyString())).thenReturn(config);
+    final Map<String, String> properties = new HashMap<String, String>();
+    Mockito.when(config.getProperties()).thenReturn(properties);
+
+    PrerequisiteCheck check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    // hdfs retry false
+    properties.put("dfs.client.retry.policy.enabled", "false");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    // hdfs retry true
+    properties.put("dfs.client.retry.policy.enabled", "true");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
+
+    // add hive
+    services.put("HIVE", Mockito.mock(Service.class));
+
+    // fail with bad property
+    properties.put("hive.metastore.failure.retries", "0");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    // add hive retry
+    properties.put("hive.metastore.failure.retries", "5");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
+
+    // add oozie
+    services.put("OOZIE", Mockito.mock(Service.class));
+
+    // fail without property
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    // fail without right property
+    properties.put("template", "foo bar baz");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    // pass with right property
+    properties.put("template", "foo bar baz -Doozie.connection.retry.count=5 foobarbaz");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckOrderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckOrderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckOrderTest.java
new file mode 100644
index 0000000..7d70311
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckOrderTest.java
@@ -0,0 +1,103 @@
+/**
+ * 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.checks;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.ControllerModule;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
+import org.springframework.core.type.filter.AssignableTypeFilter;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Tests the order of pre-upgrade checks.
+ */
+public class UpgradeCheckOrderTest {
+
+  /**
+   * Tests that instances of {@link AbstractCheckDescriptor} are ordered
+   * correctly.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testUpgradeOrder() throws Exception {
+    String sourceResourceDirectory = "src" + File.separator + "test" + File.separator + "resources";
+
+    Properties properties = new Properties();
+    properties.setProperty(Configuration.SERVER_PERSISTENCE_TYPE_KEY, "in-memory");
+    properties.setProperty(Configuration.OS_VERSION_KEY, "centos6");
+    properties.setProperty(Configuration.SHARED_RESOURCES_DIR_KEY, sourceResourceDirectory);
+
+    Injector injector = Guice.createInjector(new ControllerModule(properties));
+    UpgradeCheckRegistry registry = injector.getInstance(UpgradeCheckRegistry.class);
+    UpgradeCheckRegistry registry2 = injector.getInstance(UpgradeCheckRegistry.class);
+
+    // verify singleton
+    Assert.assertEquals(registry, registry2);
+
+    // get the check list
+    List<AbstractCheckDescriptor> checks = registry.getUpgradeChecks();
+
+    // scan for all checks
+    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
+    AssignableTypeFilter filter = new AssignableTypeFilter(AbstractCheckDescriptor.class);
+    scanner.addIncludeFilter(filter);
+
+    // verify they are equal
+    Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents("org.apache.ambari.server");
+    Assert.assertEquals(beanDefinitions.size(), checks.size());
+
+    AbstractCheckDescriptor lastCheck = null;
+    for (AbstractCheckDescriptor check : checks) {
+      UpgradeCheckGroup group = UpgradeCheckGroup.DEFAULT;
+      UpgradeCheckGroup lastGroup = UpgradeCheckGroup.DEFAULT;
+      Float order = 1.0f;
+      Float lastOrder = 1.0f;
+
+      if (null == lastCheck) {
+        lastCheck = check;
+      }
+
+      UpgradeCheck annotation = check.getClass().getAnnotation(UpgradeCheck.class);
+      UpgradeCheck lastAnnotation = lastCheck.getClass().getAnnotation(UpgradeCheck.class);
+
+      if (null != annotation) {
+        group = annotation.group();
+        order = annotation.order();
+      }
+
+      if (null != lastAnnotation) {
+        lastGroup = lastAnnotation.group();
+        lastOrder = lastAnnotation.order();
+      }
+
+      Assert.assertTrue(lastGroup.getOrder().compareTo(group.getOrder()) <= 0);
+      Assert.assertTrue(lastOrder.compareTo(order) <= 0);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/test/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheckTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheckTest.java
new file mode 100644
index 0000000..4f2da3b
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/YarnTimelineServerStatePreservingCheckTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.checks;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.google.inject.Provider;
+
+/**
+ * Tests for {@link YarnTimelineServerStatePreservingCheckTest}
+ */
+public class YarnTimelineServerStatePreservingCheckTest {
+  private final Clusters m_clusters = Mockito.mock(Clusters.class);
+
+  private final YarnTimelineServerStatePreservingCheck m_check = new YarnTimelineServerStatePreservingCheck();
+
+  /**
+   *
+   */
+  @Before
+  public void setup() {
+    m_check.clustersProvider = new Provider<Clusters>() {
+
+      @Override
+      public Clusters get() {
+        return m_clusters;
+      }
+    };
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testIsApplicable() throws Exception {
+    final Cluster cluster = Mockito.mock(Cluster.class);
+    Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(m_clusters.getCluster("cluster")).thenReturn(cluster);
+    Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP-2.2"));
+
+    Map<String, Service> services = new HashMap<String, Service>();
+    Mockito.when(cluster.getServices()).thenReturn(services);
+
+    ClusterVersionEntity clusterVersionEntity = Mockito.mock(ClusterVersionEntity.class);
+    Mockito.when(cluster.getCurrentClusterVersion()).thenReturn(clusterVersionEntity);
+
+    RepositoryVersionEntity repositoryVersionEntity = Mockito.mock(RepositoryVersionEntity.class);
+    Mockito.when(clusterVersionEntity.getRepositoryVersion()).thenReturn(repositoryVersionEntity);
+    Mockito.when(repositoryVersionEntity.getVersion()).thenReturn("2.2.4.2");
+
+    PrereqCheckRequest request = new PrereqCheckRequest("cluster");
+    request.setRepositoryVersion("2.3.0.0");
+
+    // YARN not installed
+    Assert.assertFalse(m_check.isApplicable(request));
+
+    // YARN installed
+    services.put("YARN", Mockito.mock(Service.class));
+    Assert.assertTrue(m_check.isApplicable(request));
+
+    Mockito.when(repositoryVersionEntity.getVersion()).thenReturn("2.2.0.0");
+    Assert.assertFalse(m_check.isApplicable(request));
+
+    Mockito.when(repositoryVersionEntity.getVersion()).thenReturn("2.2.4.2");
+    Assert.assertTrue(m_check.isApplicable(request));
+  }
+
+  @Test
+  public void testPerform() throws Exception {
+    final Cluster cluster = Mockito.mock(Cluster.class);
+    Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(m_clusters.getCluster("cluster")).thenReturn(cluster);
+
+    final DesiredConfig desiredConfig = Mockito.mock(DesiredConfig.class);
+    Mockito.when(desiredConfig.getTag()).thenReturn("tag");
+    Map<String, DesiredConfig> configMap = new HashMap<String, DesiredConfig>();
+    configMap.put("yarn-site", desiredConfig);
+    configMap.put("core-site", desiredConfig);
+
+    Mockito.when(cluster.getDesiredConfigs()).thenReturn(configMap);
+    final Config config = Mockito.mock(Config.class);
+    Mockito.when(cluster.getConfig(Mockito.anyString(), Mockito.anyString())).thenReturn(config);
+    final Map<String, String> properties = new HashMap<String, String>();
+    Mockito.when(config.getProperties()).thenReturn(properties);
+
+    PrerequisiteCheck check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+
+    properties.put("yarn.timeline-service.recovery.enabled", "true");
+    check = new PrerequisiteCheck(null, null);
+    m_check.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f4725228/ambari-server/src/test/java/org/apache/ambari/server/state/CheckHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/CheckHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/CheckHelperTest.java
index 17a8abe..e3836cb 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/CheckHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/CheckHelperTest.java
@@ -58,7 +58,7 @@ public class CheckHelperTest {
    */
 
   @Test
-  public void performPreUpgradeChecksTest_ok() throws Exception {
+  public void testPreUpgradeCheck() throws Exception {
     final CheckHelper helper = new CheckHelper();
     List<AbstractCheckDescriptor> updateChecksRegistry = new ArrayList<AbstractCheckDescriptor>();
     AbstractCheckDescriptor descriptor = EasyMock.createNiceMock(AbstractCheckDescriptor.class);
@@ -73,7 +73,7 @@ public class CheckHelperTest {
   }
 
   @Test
-  public void performPreUpgradeChecksTest_notApplicable() throws Exception {
+  public void testPreUpgradeCheckNotApplicable() throws Exception {
     final CheckHelper helper = new CheckHelper();
     List<AbstractCheckDescriptor> updateChecksRegistry = new ArrayList<AbstractCheckDescriptor>();
     AbstractCheckDescriptor descriptor = EasyMock.createNiceMock(AbstractCheckDescriptor.class);
@@ -85,7 +85,7 @@ public class CheckHelperTest {
   }
 
   @Test
-  public void performPreUpgradeChecksTest_throwsException() throws Exception {
+  public void testPreUpgradeCheckThrowsException() throws Exception {
     final CheckHelper helper = new CheckHelper();
     List<AbstractCheckDescriptor> updateChecksRegistry = new ArrayList<AbstractCheckDescriptor>();
     AbstractCheckDescriptor descriptor = EasyMock.createNiceMock(AbstractCheckDescriptor.class);
@@ -102,7 +102,7 @@ public class CheckHelperTest {
   }
 
   @Test
-  public void performPreUpgradeChecksTest_clusterIsMissing() throws Exception {
+  public void testPreUpgradeCheckClusterMissing() throws Exception {
     final Clusters clusters = Mockito.mock(Clusters.class);
     Mockito.when(clusters.getCluster(Mockito.anyString())).thenAnswer(new Answer<Cluster>() {
       @Override
@@ -115,6 +115,7 @@ public class CheckHelperTest {
         }
       }
     });
+
     final Injector injector = Guice.createInjector(new AbstractModule() {
 
       @Override
@@ -124,11 +125,15 @@ public class CheckHelperTest {
         bind(RepositoryVersionDAO.class).toProvider(Providers.<RepositoryVersionDAO>of(null));
         bind(RepositoryVersionHelper.class).toProvider(Providers.<RepositoryVersionHelper>of(null));
         bind(AmbariMetaInfo.class).toProvider(Providers.<AmbariMetaInfo>of(null));
+        bind(ServicesUpCheck.class).toInstance(new ServicesUpCheck());
       }
     });
+
     final CheckHelper helper = injector.getInstance(CheckHelper.class);
     List<AbstractCheckDescriptor> updateChecksRegistry = new ArrayList<AbstractCheckDescriptor>();
-    updateChecksRegistry.add(injector.getInstance(ServicesUpCheck.class)); //mocked Cluster has no services, so the check should always be PASS
+
+    // mocked Cluster has no services, so the check should always be PASS
+    updateChecksRegistry.add(injector.getInstance(ServicesUpCheck.class));
     List<PrerequisiteCheck> upgradeChecks = helper.performChecks(new PrereqCheckRequest("existing"), updateChecksRegistry);
     Assert.assertEquals(PrereqCheckStatus.PASS, upgradeChecks.get(0).getStatus());
     upgradeChecks = helper.performChecks(new PrereqCheckRequest("non-existing"), updateChecksRegistry);