You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2015/01/02 22:17:35 UTC

ambari git commit: AMBARI-8898. Implement all pre-upgrade checks (Yurii Shylov via ncole)

Repository: ambari
Updated Branches:
  refs/heads/trunk d81bc9b33 -> 64424e6ff


AMBARI-8898. Implement all pre-upgrade checks (Yurii Shylov via ncole)


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

Branch: refs/heads/trunk
Commit: 64424e6ff3f21f465f3aa479c2af82e427bd1051
Parents: d81bc9b
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Jan 2 15:56:58 2015 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Fri Jan 2 15:56:58 2015 -0500

----------------------------------------------------------------------
 .../controller/PreUpgradeCheckRequest.java      |  43 ++
 .../PreUpgradeCheckResourceProvider.java        |  31 +-
 .../ambari/server/orm/dao/HostVersionDAO.java   |   2 +-
 .../ambari/server/state/UpgradeCheckHelper.java | 454 +++++++++++++++++++
 .../ambari/server/state/UpgradeChecks.java      | 161 -------
 .../state/stack/upgrade/UpgradeCheck.java       |   2 +-
 .../server/state/UpgradeCheckHelperTest.java    |  88 ++++
 7 files changed, 607 insertions(+), 174 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/main/java/org/apache/ambari/server/controller/PreUpgradeCheckRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/PreUpgradeCheckRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/PreUpgradeCheckRequest.java
new file mode 100644
index 0000000..86619e8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/PreUpgradeCheckRequest.java
@@ -0,0 +1,43 @@
+/**
+ * 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.controller;
+
+/**
+ * Represents a pre upgrade request.
+ */
+public class PreUpgradeCheckRequest {
+  private final String clusterName;
+  private String repositoryVersionName;
+
+  //TODO make repositoryVersionName also final as soon as UI will be changed to always provide it to API
+  public PreUpgradeCheckRequest(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public String getRepositoryVersionName() {
+    return repositoryVersionName;
+  }
+
+  public void setRepositoryVersionName(String repositoryVersionName) {
+    this.repositoryVersionName = repositoryVersionName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/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 0cb20c1..009b5fe 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
@@ -24,6 +24,7 @@ import java.util.Set;
 
 import org.apache.ambari.server.StaticallyInject;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.PreUpgradeCheckRequest;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -33,7 +34,7 @@ import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-import org.apache.ambari.server.state.UpgradeChecks;
+import org.apache.ambari.server.state.UpgradeCheckHelper;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeCheck;
 
 import com.google.inject.Inject;
@@ -46,13 +47,14 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
 
   //----- Property ID constants ---------------------------------------------
 
-  public static final String UPGRADE_CHECK_ID_PROPERTY_ID           = PropertyHelper.getPropertyId("UpgradeChecks", "id");
-  public static final String UPGRADE_CHECK_CHECK_PROPERTY_ID        = PropertyHelper.getPropertyId("UpgradeChecks", "check");
-  public static final String UPGRADE_CHECK_STATUS_PROPERTY_ID       = PropertyHelper.getPropertyId("UpgradeChecks", "status");
-  public static final String UPGRADE_CHECK_REASON_PROPERTY_ID       = PropertyHelper.getPropertyId("UpgradeChecks", "reason");
-  public static final String UPGRADE_CHECK_FAILED_ON_PROPERTY_ID    = PropertyHelper.getPropertyId("UpgradeChecks", "failed_on");
-  public static final String UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID   = PropertyHelper.getPropertyId("UpgradeChecks", "check_type");
-  public static final String UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "cluster_name");
+  public static final String UPGRADE_CHECK_ID_PROPERTY_ID                 = PropertyHelper.getPropertyId("UpgradeChecks", "id");
+  public static final String UPGRADE_CHECK_CHECK_PROPERTY_ID              = PropertyHelper.getPropertyId("UpgradeChecks", "check");
+  public static final String UPGRADE_CHECK_STATUS_PROPERTY_ID             = PropertyHelper.getPropertyId("UpgradeChecks", "status");
+  public static final String UPGRADE_CHECK_REASON_PROPERTY_ID             = PropertyHelper.getPropertyId("UpgradeChecks", "reason");
+  public static final String UPGRADE_CHECK_FAILED_ON_PROPERTY_ID          = PropertyHelper.getPropertyId("UpgradeChecks", "failed_on");
+  public static final String UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID         = PropertyHelper.getPropertyId("UpgradeChecks", "check_type");
+  public static final String UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID       = PropertyHelper.getPropertyId("UpgradeChecks", "cluster_name");
+  public static final String UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("UpgradeChecks", "repository_version");
 
   @SuppressWarnings("serial")
   private static Set<String> pkPropertyIds = new HashSet<String>() {
@@ -71,6 +73,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
       add(UPGRADE_CHECK_FAILED_ON_PROPERTY_ID);
       add(UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID);
       add(UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID);
+      add(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID);
     }
   };
 
@@ -83,7 +86,7 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
   };
 
   @Inject
-  private static UpgradeChecks upgradeChecks;
+  private static UpgradeCheckHelper upgradeChecks;
 
   /**
    * Constructor.
@@ -104,8 +107,11 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
 
     for (Map<String, Object> propertyMap: propertyMaps) {
       final String clusterName = propertyMap.get(UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).toString();
-
-      for (UpgradeCheck upgradeCheck: upgradeChecks.performAll(clusterName)) {
+      final PreUpgradeCheckRequest upgradeCheckRequest = new PreUpgradeCheckRequest(clusterName);
+      if (propertyMap.containsKey(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID)) {
+        upgradeCheckRequest.setRepositoryVersionName(propertyMap.get(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).toString());
+      }
+      for (UpgradeCheck upgradeCheck: upgradeChecks.performPreUpgradeChecks(upgradeCheckRequest)) {
         final Resource resource = new ResourceImpl(Resource.Type.PreUpgradeCheck);
         setResourceProperty(resource, UPGRADE_CHECK_ID_PROPERTY_ID, upgradeCheck.getId(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_CHECK_PROPERTY_ID, upgradeCheck.getDescription(), requestedIds);
@@ -114,6 +120,9 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
         setResourceProperty(resource, UPGRADE_CHECK_FAILED_ON_PROPERTY_ID, upgradeCheck.getFailedOn(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID, upgradeCheck.getType(), requestedIds);
         setResourceProperty(resource, UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID, upgradeCheck.getClusterName(), requestedIds);
+        if (upgradeCheckRequest.getRepositoryVersionName() != null) {
+          setResourceProperty(resource, UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID, upgradeCheckRequest.getRepositoryVersionName(), requestedIds);
+        }
         resources.add(resource);
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
index 1afc850..ed9fa24 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
@@ -128,7 +128,7 @@ public class HostVersionDAO {
    * Retrieve the single host version for the given cluster, stack name, stack version, and host name.
    *
    * @param clusterName Cluster name
-   * @param stack Stack name (e.g., HDP)
+   * @param stack Stack name (e.g., HDP-2.2)
    * @param version Stack version (e.g., 2.2.0.1-995)
    * @param hostName FQDN of host
    * @return Returns the single host version that matches the criteria.

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeCheckHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeCheckHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeCheckHelper.java
new file mode 100644
index 0000000..355532f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeCheckHelper.java
@@ -0,0 +1,454 @@
+/**
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ServiceNotFoundException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.PreUpgradeCheckRequest;
+import org.apache.ambari.server.orm.dao.HostVersionDAO;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.stack.HostsType;
+import org.apache.ambari.server.stack.MasterHostResolver;
+import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeCheck;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeCheckStatus;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeCheckType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Manages pre-upgrade checks.
+ */
+@Singleton
+public class UpgradeCheckHelper {
+
+  /**
+   * Log.
+   */
+  private static Logger LOG = LoggerFactory.getLogger(UpgradeCheckHelper.class);
+
+  /**
+   * List of all possible upgrade checks.
+   */
+  final List<UpgradeCheckDescriptor> registry = new ArrayList<UpgradeCheckDescriptor>();
+
+  @Inject
+  Provider<Clusters> clustersProvider;
+
+  @Inject
+  Provider<Configuration> configurationProvider;
+
+  @Inject
+  Provider<HostVersionDAO> hostVersionDaoProvider;
+
+  @Inject
+  Provider<RepositoryVersionDAO> repositoryVersionDaoProvider;
+
+  /**
+   * Constructor. Fills upgrade check registry upon creation.
+   */
+  public UpgradeCheckHelper() {
+    registry.add(new HostsHeartbeatCheck());
+    registry.add(new HostsMasterMaintenanceCheck());
+    registry.add(new HostsRepositoryVersionCheck());
+    registry.add(new ServicesMaintenanceModeCheck());
+    registry.add(new ServicesNamenodeHighAvailabilityCheck());
+    registry.add(new ServicesYarnWorkPreservingCheck());
+    registry.add(new ServicesDecommissionCheck());
+    registry.add(new ServicesJobsDistributedCacheCheck());
+  }
+
+  /**
+   * Executes all registered pre upgrade checks.
+   *
+   * @param request pre upgrade check request
+   * @return list of upgrade check results
+   */
+  public List<UpgradeCheck> performPreUpgradeChecks(PreUpgradeCheckRequest request) {
+    final String clusterName = request.getClusterName();
+    final List<UpgradeCheck> upgradeCheckResults = new ArrayList<UpgradeCheck>();
+    for (UpgradeCheckDescriptor upgradeCheckDescriptor: registry) {
+      final UpgradeCheck upgradeCheck = new UpgradeCheck(
+          upgradeCheckDescriptor.id, upgradeCheckDescriptor.description,
+          upgradeCheckDescriptor.type, clusterName);
+      try {
+        if (upgradeCheckDescriptor.isApplicable(request)) {
+          upgradeCheckDescriptor.perform(upgradeCheck, request);
+          upgradeCheckResults.add(upgradeCheck);
+        }
+      } catch (Exception ex) {
+        LOG.error("Pre-upgrade check " + upgradeCheckDescriptor.id + " failed", ex);
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Unexpected server error happened");
+        upgradeCheckResults.add(upgradeCheck);
+      }
+    }
+    return upgradeCheckResults;
+  }
+
+  /**
+   * Describes upgrade check.
+   */
+  protected abstract class UpgradeCheckDescriptor {
+
+    private final String id;
+    private final String description;
+    private final UpgradeCheckType type;
+
+    /**
+     * Constructor.
+     *
+     * @param id unique identifier
+     * @param type type
+     * @param description description
+     */
+    public UpgradeCheckDescriptor(String id, UpgradeCheckType type, String description) {
+      this.id = id;
+      this.type = type;
+      this.description = description;
+    }
+
+    /**
+     * Tests if the upgrade check is applicable to given cluster. By default returns true.
+     *
+     * @param request pre upgrade check request
+     * @return true if check should be performed
+     *
+     * @throws AmbariException if server error happens
+     */
+    public boolean isApplicable(PreUpgradeCheckRequest request) throws AmbariException {
+      return true;
+    }
+
+    /**
+     * Executes check against given cluster.
+     *
+     * @param upgradeCheck dto for upgrade check results
+     * @param request pre upgrade check request
+     *
+     * @throws AmbariException if server error happens
+     */
+    public abstract void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException;
+  }
+
+  /**
+   * Checks that services are in the maintenance mode.
+   */
+  protected class ServicesMaintenanceModeCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public ServicesMaintenanceModeCheck() {
+      super("SERVICES_MAINTENANCE_MODE", UpgradeCheckType.SERVICE, "No service can be in maintenance mode");
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      for (Map.Entry<String, Service> serviceEntry : cluster.getServices().entrySet()) {
+        final Service service = serviceEntry.getValue();
+        if (service.getDesiredState() != State.STARTED || service.getMaintenanceState() == MaintenanceState.ON) {
+          upgradeCheck.getFailedOn().add(service.getName());
+        }
+      }
+      if (!upgradeCheck.getFailedOn().isEmpty()) {
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Some services are in Maintenance Mode");
+      }
+    }
+  }
+
+  /**
+   * Checks that all hosts are either in maintenance mode or heartbeating with the server.
+   */
+  protected class HostsHeartbeatCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public HostsHeartbeatCheck() {
+      super("HOSTS_HEARTBEAT", UpgradeCheckType.HOST, "All hosts must be heartbeating with the server unless they are in Maintenance Mode");
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      final Map<String, Host> clusterHosts = clustersProvider.get().getHostsForCluster(clusterName);
+      for (Map.Entry<String, Host> hostEntry : clusterHosts.entrySet()) {
+        final Host host = hostEntry.getValue();
+        if (host.getHealthStatus().getHealthStatus() == HealthStatus.UNKNOWN && host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.OFF) {
+          upgradeCheck.getFailedOn().add(host.getHostName());
+        }
+      }
+      if (!upgradeCheck.getFailedOn().isEmpty()) {
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Some hosts are not heartbeating with the server");
+      }
+    }
+  }
+
+  /**
+   * Checks that all hosts in maintenance state do not have master components.
+   */
+  protected class HostsMasterMaintenanceCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public HostsMasterMaintenanceCheck() {
+      super("HOSTS_MASTER_MAINTENANCE", UpgradeCheckType.HOST, "Hosts in Maintenance Mode must not have any master components");
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      final MasterHostResolver masterHostResolver = new MasterHostResolver(cluster);
+      final Set<String> hostsWithMasterComponent = new HashSet<String>();
+      for (Entry<String, Service> serviceEntry: cluster.getServices().entrySet()) {
+        final Service service = serviceEntry.getValue();
+        for (Entry<String, ServiceComponent> serviceComponentEntry: service.getServiceComponents().entrySet()) {
+          final ServiceComponent serviceComponent = serviceComponentEntry.getValue();
+          final HostsType hostsType = masterHostResolver.getMasterAndHosts(service.getName(), serviceComponent.getName());
+          if (hostsType != null && hostsType.master != null) {
+            hostsWithMasterComponent.add(hostsType.master);
+          }
+        }
+      }
+      final Map<String, Host> clusterHosts = clustersProvider.get().getHostsForCluster(clusterName);
+      for (Map.Entry<String, Host> hostEntry : clusterHosts.entrySet()) {
+        final Host host = hostEntry.getValue();
+        if (host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.ON && hostsWithMasterComponent.contains(host.getHostName())) {
+          upgradeCheck.getFailedOn().add(host.getHostName());
+        }
+      }
+      if (!upgradeCheck.getFailedOn().isEmpty()) {
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Some hosts with master components are in Maintenance Mode");
+      }
+    }
+  }
+
+  /**
+   * Checks that all hosts have particular repository version.
+   */
+  protected class HostsRepositoryVersionCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public HostsRepositoryVersionCheck() {
+      super("HOSTS_REPOSITORY_VERSION", UpgradeCheckType.HOST, "Hosts should have the new repository version installed");
+    }
+
+    @Override
+    public boolean isApplicable(PreUpgradeCheckRequest request) throws AmbariException {
+      return request.getRepositoryVersionName() != null;
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      final Map<String, Host> clusterHosts = clustersProvider.get().getHostsForCluster(clusterName);
+      for (Map.Entry<String, Host> hostEntry : clusterHosts.entrySet()) {
+        final Host host = hostEntry.getValue();
+        if (host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.OFF) {
+          final RepositoryVersionEntity repositoryVersion = repositoryVersionDaoProvider.get().findByDisplayName(request.getRepositoryVersionName());
+          final HostVersionEntity hostVersion = hostVersionDaoProvider.get().findByClusterStackVersionAndHost(clusterName, repositoryVersion.getStack(), repositoryVersion.getVersion(), host.getHostName());
+          if (hostVersion == null || hostVersion.getState() != RepositoryVersionState.INSTALLED) {
+            upgradeCheck.getFailedOn().add(host.getHostName());
+          }
+        }
+      }
+      if (!upgradeCheck.getFailedOn().isEmpty()) {
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Some hosts do not have repository version " + request.getRepositoryVersionName() + " installed");
+      }
+
+    }
+  }
+
+  /**
+   * Checks that namenode high availability is enabled.
+   */
+  protected class ServicesNamenodeHighAvailabilityCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public ServicesNamenodeHighAvailabilityCheck() {
+      super("SERVICES_NAMENODE_HA", UpgradeCheckType.SERVICE, "Namenode high availability should be enabled");
+    }
+
+    @Override
+    public boolean isApplicable(PreUpgradeCheckRequest request) throws AmbariException {
+      final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+      return cluster.getService("HDFS") != null;
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      final String configType = "hdfs-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("dfs.nameservices")) {
+        upgradeCheck.getFailedOn().add("HDFS");
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("Namenode high availability is disabled");
+      }
+    }
+  }
+
+  /**
+   * Checks that YARN has work-preserving restart enabled.
+   */
+  protected class ServicesYarnWorkPreservingCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public ServicesYarnWorkPreservingCheck() {
+      super("SERVICES_YARN_WP", UpgradeCheckType.SERVICE, "YARN work preserving restart should be enabled");
+    }
+
+    @Override
+    public boolean isApplicable(PreUpgradeCheckRequest request) throws AmbariException {
+      final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+      try {
+        cluster.getService("YARN");
+      } catch (ServiceNotFoundException ex) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest 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") ||
+          !Boolean.getBoolean(config.getProperties().get("yarn.resourcemanager.work-preserving-recovery.enabled"))) {
+        upgradeCheck.getFailedOn().add("YARN");
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("YARN doesn't have work preserving restart, yarn.resourcemanager.work-preserving-recovery.enabled property is missing");
+      }
+    }
+  }
+
+  /**
+   * Checks that there are no services in decommission state.
+   */
+  protected class ServicesDecommissionCheck extends UpgradeCheckDescriptor {
+
+    /**
+     * Constructor.
+     */
+    public ServicesDecommissionCheck() {
+      super("SERVICES_DECOMMISSION", UpgradeCheckType.SERVICE, "Services should not be in Decommission state");
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      for (Entry<String, Service> serviceEntry: cluster.getServices().entrySet()) {
+        final Service service = serviceEntry.getValue();
+        for (Entry<String, ServiceComponent> serviceComponentEntry: service.getServiceComponents().entrySet()) {
+          final ServiceComponent serviceComponent = serviceComponentEntry.getValue();
+          for (String hostName : serviceComponent.getServiceComponentHosts().keySet()) {
+            final ServiceComponentHost scHost = serviceComponent.getServiceComponentHost(hostName);
+            if (scHost.getComponentAdminState() == HostComponentAdminState.DECOMMISSIONED || scHost.getComponentAdminState() == HostComponentAdminState.DECOMMISSIONING) {
+              upgradeCheck.getFailedOn().add(serviceComponent.getName());
+            }
+          }
+        }
+      }
+      if (!upgradeCheck.getFailedOn().isEmpty()) {
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("There are services in decommission or decommissioning state");
+      }
+    }
+  }
+
+  /**
+   * Checks that MR, Oozie and Tez jobs reference hadoop libraries from the distributed cache.
+   */
+  protected class ServicesJobsDistributedCacheCheck extends UpgradeCheckDescriptor {
+
+    @Override
+    public boolean isApplicable(PreUpgradeCheckRequest request)
+        throws AmbariException {
+      final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
+      try {
+        cluster.getService("YARN");
+      } catch (ServiceNotFoundException ex) {
+        return false;
+      }
+      return true;
+    }
+
+    /**
+     * Constructor.
+     */
+    public ServicesJobsDistributedCacheCheck() {
+      super("SERVICES_JOBS_DISTRIBUTED_CACHE", UpgradeCheckType.SERVICE, "Jobs should reference hadoop libraries from the distributed cache");
+    }
+
+    @Override
+    public void perform(UpgradeCheck upgradeCheck, PreUpgradeCheckRequest request) throws AmbariException {
+      final String clusterName = request.getClusterName();
+      final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+      final String configType = "mapred-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("mapreduce.application.framework.path") || !config.getProperties().containsKey("mapreduce.application.classpath")) {
+        // TODO actually it is needed to validate that these properties contain proper values but the tickets for these changes are still open, so it will cause
+        // preupgrade checks to fail
+        upgradeCheck.getFailedOn().add("MR");
+        upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
+        upgradeCheck.setFailReason("mapreduce.application.framework.path and mapreduce.application.classpath should reference distributed cache");
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeChecks.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeChecks.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeChecks.java
deleted file mode 100644
index 83cd632..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeChecks.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.state;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeCheck;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeCheckStatus;
-import org.apache.ambari.server.state.stack.upgrade.UpgradeCheckType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-
-/**
- * Manages pre-upgrade checks.
- */
-@Singleton
-public class UpgradeChecks {
-
-  /**
-   * Log.
-   */
-  private static Logger LOG = LoggerFactory.getLogger(UpgradeChecks.class);
-
-  /**
-   * List of all possible upgrade checks.
-   */
-  private static final List<UpgradeCheckDescriptor> UPGRADE_CHECK_REGISTRY = new ArrayList<UpgradeCheckDescriptor>();
-
-  @Inject
-  Provider<Clusters> clustersProvider;
-
-  /**
-   * Constructor. Fills upgrade check registry upon creation.
-   */
-  public UpgradeChecks() {
-    UPGRADE_CHECK_REGISTRY.add(new UpgradeCheckDescriptor() {
-
-      @Override
-      public UpgradeCheck perform(String clusterName) {
-        final UpgradeCheck upgradeCheck = new UpgradeCheck(
-            "SERVICES_MAINTENANCE_MODE",
-            "All services must not be in Maintenance Mode",
-            UpgradeCheckType.SERVICE,
-            clusterName);
-
-        try {
-          final Cluster cluster = clustersProvider.get().getCluster(clusterName);
-          for (Map.Entry<String, Service> serviceEntry: cluster.getServices().entrySet()) {
-            final Service service = serviceEntry.getValue();
-            if (service.getMaintenanceState() == MaintenanceState.ON) {
-              upgradeCheck.getFailedOn().add(service.getName());
-            }
-          }
-          if (upgradeCheck.getFailedOn().isEmpty()) {
-            upgradeCheck.setStatus(UpgradeCheckStatus.PASS);
-          } else {
-            upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
-            upgradeCheck.setFailReason("Some services are in Maintenance Mode");
-          }
-        } catch (AmbariException ex) {
-          LOG.error("Pre-upgrade check " + upgradeCheck.getId() + " failed", ex);
-          upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
-          upgradeCheck.setFailReason("Unexpected server error happened");
-        }
-
-        return upgradeCheck;
-      }
-    });
-
-    UPGRADE_CHECK_REGISTRY.add(new UpgradeCheckDescriptor() {
-
-      @Override
-      public UpgradeCheck perform(String clusterName) {
-        final UpgradeCheck upgradeCheck = new UpgradeCheck(
-            "HOST_HEARTBEAT",
-            "All hosts must be heartbeating with the server unless they are in Maintenance Mode",
-            UpgradeCheckType.HOST,
-            clusterName);
-
-        try {
-          final Map<String, Host> clusterHosts = clustersProvider.get().getHostsForCluster(clusterName);
-          for (Map.Entry<String, Host> hostEntry: clusterHosts.entrySet()) {
-            final Host host = hostEntry.getValue();
-            if (host.getHealthStatus().getHealthStatus() == HealthStatus.UNKNOWN) {
-              upgradeCheck.getFailedOn().add(host.getHostName());
-            }
-          }
-          if (upgradeCheck.getFailedOn().isEmpty()) {
-            upgradeCheck.setStatus(UpgradeCheckStatus.PASS);
-          } else {
-            upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
-            upgradeCheck.setFailReason("Some hosts are not heartbeating with the server");
-          }
-        } catch (AmbariException ex) {
-          LOG.error("Pre-upgrade check " + upgradeCheck.getId() + " failed", ex);
-          upgradeCheck.setStatus(UpgradeCheckStatus.FAIL);
-          upgradeCheck.setFailReason("Unexpected server error happened");
-        }
-
-        return upgradeCheck;
-      }
-    });
-  }
-
-  public List<UpgradeCheck> performAll(String clusterName) {
-    final List<UpgradeCheck> upgradeCheckResults = new ArrayList<UpgradeCheck>();
-    for (UpgradeCheckDescriptor upgradeCheck: UPGRADE_CHECK_REGISTRY) {
-      if (upgradeCheck.isApplicable()) {
-        upgradeCheckResults.add(upgradeCheck.perform(clusterName));
-      }
-    }
-    return upgradeCheckResults;
-  }
-
-  /**
-   * Describes upgrade check.
-   */
-  private abstract class UpgradeCheckDescriptor {
-
-    /**
-     * By default returns true.
-     *
-     * @return true if check should be performed
-     */
-    public boolean isApplicable() {
-      return true;
-    }
-
-    /**
-     * Executes check against given cluster.
-     *
-     * @param clusterName cluster name
-     * @return the results of the check
-     */
-    public abstract UpgradeCheck perform(String clusterName);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeCheck.java
index 0d85a93..80c4bbf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/UpgradeCheck.java
@@ -29,7 +29,7 @@ public class UpgradeCheck {
   private final String description;
   private final UpgradeCheckType type;
   private final String clusterName;
-  private UpgradeCheckStatus status;
+  private UpgradeCheckStatus status = UpgradeCheckStatus.PASS;
   private String failReason = "";
   private List<String> failedOn = new ArrayList<String>();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/64424e6f/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeCheckHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeCheckHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeCheckHelperTest.java
new file mode 100644
index 0000000..2cbe088
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeCheckHelperTest.java
@@ -0,0 +1,88 @@
+/**
+ * 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;
+
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PreUpgradeCheckRequest;
+import org.apache.ambari.server.state.UpgradeCheckHelper.UpgradeCheckDescriptor;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeCheck;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeCheckStatus;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+/**
+ * Tests the {@link UpgradeCheckHelper} class
+ */
+public class UpgradeCheckHelperTest {
+
+  /**
+   * Makes sure that people don't forget to add new checks to registry.
+   */
+  @Test
+  public void defaultConstructorTest() throws Exception {
+    final UpgradeCheckHelper helper = new UpgradeCheckHelper();
+
+    Assert.assertEquals(UpgradeCheckHelper.class.getDeclaredClasses().length - 1, helper.registry.size());
+  }
+
+  @Test
+  public void performPreUpgradeChecksTest_ok() throws Exception {
+    final UpgradeCheckHelper helper = new UpgradeCheckHelper();
+    helper.registry.clear();
+    UpgradeCheckDescriptor descriptor = EasyMock.createNiceMock(UpgradeCheckDescriptor.class);
+    descriptor.perform(EasyMock.<UpgradeCheck> anyObject(), EasyMock.<PreUpgradeCheckRequest> anyObject());
+    EasyMock.expectLastCall().times(1);
+    EasyMock.expect(descriptor.isApplicable(EasyMock.<PreUpgradeCheckRequest> anyObject())).andReturn(true);
+    EasyMock.replay(descriptor);
+    helper.registry.add(descriptor);
+    helper.performPreUpgradeChecks(new PreUpgradeCheckRequest("cluster"));
+    EasyMock.verify(descriptor);
+  }
+
+  @Test
+  public void performPreUpgradeChecksTest_notApplicable() throws Exception {
+    final UpgradeCheckHelper helper = new UpgradeCheckHelper();
+    helper.registry.clear();
+    UpgradeCheckDescriptor descriptor = EasyMock.createNiceMock(UpgradeCheckDescriptor.class);
+    EasyMock.expect(descriptor.isApplicable(EasyMock.<PreUpgradeCheckRequest> anyObject())).andReturn(false);
+    EasyMock.replay(descriptor);
+    helper.registry.add(descriptor);
+    helper.performPreUpgradeChecks(new PreUpgradeCheckRequest("cluster"));
+    EasyMock.verify(descriptor);
+  }
+
+  @Test
+  public void performPreUpgradeChecksTest_throwsException() throws Exception {
+    final UpgradeCheckHelper helper = new UpgradeCheckHelper();
+    helper.registry.clear();
+    UpgradeCheckDescriptor descriptor = EasyMock.createNiceMock(UpgradeCheckDescriptor.class);
+    descriptor.perform(EasyMock.<UpgradeCheck> anyObject(), EasyMock.<PreUpgradeCheckRequest> anyObject());
+    EasyMock.expectLastCall().andThrow(new AmbariException("error"));
+    EasyMock.expect(descriptor.isApplicable(EasyMock.<PreUpgradeCheckRequest> anyObject())).andReturn(true);
+    EasyMock.replay(descriptor);
+    helper.registry.add(descriptor);
+    final List<UpgradeCheck> upgradeChecks = helper.performPreUpgradeChecks(new PreUpgradeCheckRequest("cluster"));
+    EasyMock.verify(descriptor);
+    Assert.assertEquals(UpgradeCheckStatus.FAIL, upgradeChecks.get(0).getStatus());
+  }
+
+}