Bladeren bron

AMBARI-10874 - Pre-Upgrade Checks Should Know Which Stack They Are Valid (jonathanhurley)

Jonathan Hurley 10 jaren geleden
bovenliggende
commit
fea608d052
17 gewijzigde bestanden met toevoegingen van 401 en 18 verwijderingen
  1. 65 3
      ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java
  2. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java
  3. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java
  4. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java
  5. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java
  6. 5 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java
  7. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java
  8. 5 2
      ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java
  9. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java
  10. 42 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java
  11. 40 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java
  12. 18 8
      ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java
  13. 8 1
      ambari-server/src/test/java/org/apache/ambari/server/checks/HostsHeartbeatCheckTest.java
  14. 8 1
      ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesDecommissionCheckTest.java
  15. 8 1
      ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheckTest.java
  16. 8 1
      ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java
  17. 170 0
      ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckStackVersionTest.java

+ 65 - 3
ambari-server/src/main/java/org/apache/ambari/server/checks/AbstractCheckDescriptor.java

@@ -29,6 +29,7 @@ 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.ServiceInfo;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.PrereqCheckType;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
@@ -45,6 +46,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 String DEFAULT = "default";
 
@@ -75,17 +78,66 @@ public abstract class AbstractCheckDescriptor {
   }
 
   /**
-   * Tests if the prerequisite check is applicable to given cluster. By default returns true.
+   * Tests if the prerequisite check is applicable to given cluster. This
+   * method's defautl logic is to ensure that the cluster stack source and
+   * target are compatible with the prerequisite check. When overridding this
+   * method, call {@code super#isApplicable(PrereqCheckRequest)}.
    *
-   * @param request prerequisite check request
+   * @param request
+   *          prerequisite check request
    * @return true if check should be performed
    *
-   * @throws org.apache.ambari.server.AmbariException if server error happens
+   * @throws org.apache.ambari.server.AmbariException
+   *           if server error happens
    */
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    StackId sourceStackId = getSourceStack();
+    StackId targetStackId = getTargetStack();
+
+    if( null == sourceStackId && null == targetStackId ) {
+      return true;
+    }
+
+    StackId requestSourceStack = request.getSourceStackId();
+    if (null != sourceStackId && null != requestSourceStack
+        && sourceStackId.compareTo(requestSourceStack) > 0) {
+      return false;
+    }
+
+    StackId requestTargetStack = request.getTargetStackId();
+    if (null != targetStackId && null != requestTargetStack
+        && targetStackId.compareTo(requestTargetStack) < 0) {
+      return false;
+    }
+
     return true;
   }
 
+  /**
+   * Gets the earliest stack that the upgrade check is compatible with. By
+   * default, all checks will return {@link #STACK_HDP_22} since this is the
+   * first version of HDP that supports automated upgrades.
+   *
+   * @return the earliest stack that the upgrade check is compatible with, or
+   *         {@code null} for all.
+   */
+  public StackId getSourceStack(){
+    return STACK_HDP_22;
+  }
+
+  /**
+   * Gets the most recent stack that the upgrade check is compatible with. By
+   * default, this will return {@code null} to indicate all future stacks are
+   * compatible. If an upgrade check is not compatible with a future stack, then
+   * this method should be overridden.
+   *
+   * @return the most recent stack that the upgrade check is compatible with, or
+   *         {@code null} for all.
+   */
+  public StackId getTargetStack() {
+    return null;
+  }
+
   /**
    * Executes check against given cluster.
    *
@@ -97,10 +149,20 @@ public abstract class AbstractCheckDescriptor {
   public abstract void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException;
 
 
+  /**
+   * Gets the description of the check.
+   *
+   * @return the description (not {@code null}).
+   */
   public CheckDescription getDescription() {
     return m_description;
   }
 
+  /**
+   * Gets the type of check.
+   *
+   * @return the type of check (not {@code null}).
+   */
   public PrereqCheckType getType() {
     return m_description.getType();
   }

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java

@@ -48,6 +48,10 @@ public class ConfigurationMergeCheck extends AbstractCheckDescriptor {
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     String repoVersion = request.getRepositoryVersion();
     if (null == repoVersion) {
       return false;

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/HostsMasterMaintenanceCheck.java

@@ -51,6 +51,10 @@ public class HostsMasterMaintenanceCheck extends AbstractCheckDescriptor {
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     return request.getRepositoryVersion() != null;
   }
 

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/HostsRepositoryVersionCheck.java

@@ -48,6 +48,10 @@ public class HostsRepositoryVersionCheck extends AbstractCheckDescriptor {
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     return request.getRepositoryVersion() != null;
   }
 

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/SecondaryNamenodeDeletedCheck.java

@@ -50,6 +50,10 @@ public class SecondaryNamenodeDeletedCheck extends AbstractCheckDescriptor {
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
     try {
       cluster.getService("HDFS");

+ 5 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesMapReduceDistributedCacheCheck.java

@@ -43,6 +43,11 @@ public class ServicesMapReduceDistributedCacheCheck extends AbstractCheckDescrip
   @Override
   public boolean isApplicable(PrereqCheckRequest request)
     throws AmbariException {
+
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
     try {
       cluster.getService("YARN");

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesNamenodeHighAvailabilityCheck.java

@@ -42,6 +42,10 @@ public class ServicesNamenodeHighAvailabilityCheck extends AbstractCheckDescript
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
     try {
       cluster.getService("HDFS");

+ 5 - 2
ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesTezDistributedCacheCheck.java

@@ -43,8 +43,11 @@ public class ServicesTezDistributedCacheCheck extends AbstractCheckDescriptor {
   static final String KEY_USE_HADOOP_LIBS_FALSE = "tez_use_hadoop_libs_false";
 
   @Override
-  public boolean isApplicable(PrereqCheckRequest request)
-    throws AmbariException {
+  public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
     try {
       cluster.getService("TEZ");

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesYarnWorkPreservingCheck.java

@@ -43,6 +43,10 @@ public class ServicesYarnWorkPreservingCheck extends AbstractCheckDescriptor {
 
   @Override
   public boolean isApplicable(PrereqCheckRequest request) throws AmbariException {
+    if (!super.isApplicable(request)) {
+      return false;
+    }
+
     final Cluster cluster = clustersProvider.get().getCluster(request.getClusterName());
     try {
       cluster.getService("YARN");

+ 42 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/PrereqCheckRequest.java

@@ -21,6 +21,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.ambari.server.checks.CheckDescription;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 
 /**
@@ -29,6 +30,9 @@ import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 public class PrereqCheckRequest {
   private String m_clusterName;
   private String m_repositoryVersion;
+  private StackId m_sourceStackId;
+  private StackId m_targetStackId;
+
   private Map<CheckDescription, PrereqCheckStatus> m_results =
       new HashMap<CheckDescription, PrereqCheckStatus>();
 
@@ -65,4 +69,42 @@ public class PrereqCheckRequest {
   public PrereqCheckStatus getResult(CheckDescription description) {
     return m_results.get(description);
   }
+
+  /**
+   * Gets the cluster's current stack before upgrade.
+   *
+   * @return the sourceStackId the source stack ID.
+   */
+  public StackId getSourceStackId() {
+    return m_sourceStackId;
+  }
+
+  /**
+   * Sets the cluster's current stack before upgrade.
+   *
+   * @param sourceStackId
+   *          the sourceStackId to set
+   */
+  public void setSourceStackId(StackId sourceStackId) {
+    m_sourceStackId = sourceStackId;
+  }
+
+  /**
+   * Gets the target stack of the upgrade.
+   *
+   * @return the targetStackId
+   */
+  public StackId getTargetStackId() {
+    return m_targetStackId;
+  }
+
+  /**
+   * Sets the target stack of the upgrade.
+   *
+   * @param targetStackId
+   *          the targetStackId to set
+   */
+  public void setTargetStackId(StackId targetStackId) {
+    m_targetStackId = targetStackId;
+  }
 }

+ 40 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PreUpgradeCheckResourceProvider.java

@@ -25,6 +25,7 @@ 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;
@@ -50,11 +51,16 @@ 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.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.CheckHelper;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 /**
  * Resource provider for pre-upgrade checks.
@@ -75,29 +81,46 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
 
   @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.
@@ -160,10 +183,26 @@ public class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {
 
     for (Map<String, Object> propertyMap: propertyMaps) {
       final String clusterName = propertyMap.get(UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).toString();
+      final Cluster cluster;
+
+      try {
+        cluster = clustersProvider.get().getCluster(clusterName);
+      } catch (AmbariException ambariException) {
+        throw new NoSuchResourceException(ambariException.getMessage());
+      }
+
       final PrereqCheckRequest upgradeCheckRequest = new PrereqCheckRequest(clusterName);
+      upgradeCheckRequest.setSourceStackId(cluster.getCurrentStackVersion());
+
       if (propertyMap.containsKey(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID)) {
-        upgradeCheckRequest.setRepositoryVersion(propertyMap.get(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).toString());
+        String repositoryVersionId = propertyMap.get(UPGRADE_CHECK_REPOSITORY_VERSION_PROPERTY_ID).toString();
+        RepositoryVersionEntity repositoryVersionEntity = repositoryVersionDAO.findMaxByVersion(repositoryVersionId);
+
+        // set some required properties on the check request
+        upgradeCheckRequest.setRepositoryVersion(repositoryVersionId);
+        upgradeCheckRequest.setTargetStackId(repositoryVersionEntity.getStackId());
       }
+
       for (PrerequisiteCheck prerequisiteCheck : checkHelper.performChecks(upgradeCheckRequest, updateChecksRegistry)) {
         final Resource resource = new ResourceImpl(Resource.Type.PreUpgradeCheck);
         setResourceProperty(resource, UPGRADE_CHECK_ID_PROPERTY_ID, prerequisiteCheck.getId(), requestedIds);

+ 18 - 8
ambari-server/src/main/java/org/apache/ambari/server/state/StackId.java

@@ -82,6 +82,9 @@ public class StackId implements Comparable<StackId> {
     parseStackIdHelper(this, stackId);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public boolean equals(Object object) {
     if (!(object instanceof StackId)) {
@@ -94,6 +97,9 @@ public class StackId implements Comparable<StackId> {
     return stackName.equals(s.stackName) && stackVersion.equals(s.stackVersion);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public int hashCode() {
     int result = stackName != null ? stackName.hashCode() : 0;
@@ -101,6 +107,9 @@ public class StackId implements Comparable<StackId> {
     return result;
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public int compareTo(StackId other) {
     if (this == other) {
@@ -120,26 +129,27 @@ public class StackId implements Comparable<StackId> {
     return returnValue;
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public String toString() {
     return getStackId();
   }
 
-  public static void parseStackIdHelper(StackId stackVersion,
-      String stackId) {
+  private void parseStackIdHelper(StackId stackVersion, String stackId) {
     if (stackId == null || stackId.isEmpty()) {
       stackVersion.stackName = "";
       stackVersion.stackVersion = "";
       return;
     }
+
     int pos = stackId.indexOf('-');
-    if (pos == -1
-        || (stackId.length() <= (pos+1))) {
-      throw new RuntimeException("Could not parse invalid Stack Id"
-          + ", stackId=" + stackId);
+    if (pos == -1 || (stackId.length() <= (pos + 1))) {
+      throw new RuntimeException("Could not parse invalid Stack Id" + ", stackId=" + stackId);
     }
+
     stackVersion.stackName = stackId.substring(0, pos);
-    stackVersion.stackVersion = stackId.substring(pos+1);
+    stackVersion.stackVersion = stackId.substring(pos + 1);
   }
-
 }

+ 8 - 1
ambari-server/src/test/java/org/apache/ambari/server/checks/HostsHeartbeatCheckTest.java

@@ -27,6 +27,7 @@ import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.MaintenanceState;
+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;
@@ -44,7 +45,12 @@ public class HostsHeartbeatCheckTest {
 
   @Test
   public void testIsApplicable() throws Exception {
-    Assert.assertTrue(new HostsHeartbeatCheck().isApplicable(null));
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    Assert.assertTrue(new HostsHeartbeatCheck().isApplicable(checkRequest));
   }
 
   @Test
@@ -60,6 +66,7 @@ public class HostsHeartbeatCheckTest {
 
     final Cluster cluster = Mockito.mock(Cluster.class);
     Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP", "2.2"));
     Mockito.when(clusters.getCluster("cluster")).thenReturn(cluster);
     final Map<String, Host> hosts = new HashMap<String, Host>();
     final Host host1 = Mockito.mock(Host.class);

+ 8 - 1
ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesDecommissionCheckTest.java

@@ -29,6 +29,7 @@ import org.apache.ambari.server.state.HostComponentAdminState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
+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;
@@ -46,7 +47,12 @@ public class ServicesDecommissionCheckTest {
 
   @Test
   public void testIsApplicable() throws Exception {
-    Assert.assertTrue(new ServicesDecommissionCheck().isApplicable(null));
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    Assert.assertTrue(new ServicesDecommissionCheck().isApplicable(checkRequest));
   }
 
   @Test
@@ -68,6 +74,7 @@ public class ServicesDecommissionCheckTest {
 
     final Cluster cluster = Mockito.mock(Cluster.class);
     Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP", "2.2"));
     Mockito.when(clusters.getCluster("cluster")).thenReturn(cluster);
     final Service service = Mockito.mock(Service.class);
     Mockito.when(cluster.getServices()).thenReturn(Collections.singletonMap("service", service));

+ 8 - 1
ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesMaintenanceModeCheckTest.java

@@ -24,6 +24,7 @@ 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.Service;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
@@ -42,7 +43,12 @@ public class ServicesMaintenanceModeCheckTest {
 
   @Test
   public void testIsApplicable() throws Exception {
-    Assert.assertTrue(new ServicesMaintenanceModeCheck().isApplicable(null));
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    Assert.assertTrue(new ServicesMaintenanceModeCheck().isApplicable(checkRequest));
   }
 
   @Test
@@ -65,6 +71,7 @@ public class ServicesMaintenanceModeCheckTest {
 
     final Cluster cluster = Mockito.mock(Cluster.class);
     Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP", "2.2"));
     Mockito.when(clusters.getCluster("cluster")).thenReturn(cluster);
     final Service service = Mockito.mock(Service.class);
     Mockito.when(cluster.getServices()).thenReturn(Collections.singletonMap("service", service));

+ 8 - 1
ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java

@@ -24,6 +24,7 @@ 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.Service;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
@@ -42,7 +43,12 @@ public class ServicesUpCheckTest {
 
   @Test
   public void testIsApplicable() throws Exception {
-    Assert.assertTrue(new ServicesUpCheck().isApplicable(null));
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    Assert.assertTrue(new ServicesUpCheck().isApplicable(checkRequest));
   }
 
   @Test
@@ -66,6 +72,7 @@ public class ServicesUpCheckTest {
 
     final Cluster cluster = Mockito.mock(Cluster.class);
     Mockito.when(cluster.getClusterId()).thenReturn(1L);
+    Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP", "2.2"));
     Mockito.when(clusters.getCluster("cluster")).thenReturn(cluster);
     final Service service = Mockito.mock(Service.class);
     Mockito.when(cluster.getServices()).thenReturn(Collections.singletonMap("service", service));

+ 170 - 0
ambari-server/src/test/java/org/apache/ambari/server/checks/UpgradeCheckStackVersionTest.java

@@ -0,0 +1,170 @@
+/**
+ * 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 junit.framework.Assert;
+
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.state.StackId;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+
+/**
+ * Tests that the {@link AbstractCheckDescriptor} instances will return the
+ * correct values for
+ * {@link AbstractCheckDescriptor#isApplicable(org.apache.ambari.server.controller.PrereqCheckRequest)}
+ * when different stack versions are present.
+ */
+public class UpgradeCheckStackVersionTest {
+
+  @Test
+  public void testUpgradeCheckForMoreRecentStack() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(new StackId("HDP-2.3"));
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(new StackId("HDP-2.3"));
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    // false because the upgrade is for 2.2->2.2 and the check starts at 2.3
+    Assert.assertFalse(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+
+  @Test
+  public void testUpgradeCheckForOlderStack() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(new StackId("HDP-2.2"));
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(new StackId("HDP-2.2"));
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.3.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.3"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.3"));
+
+    // false because the upgrade is for 2.3->2.3 and the check is only for 2.2
+    Assert.assertFalse(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+
+  @Test
+  public void testUpgradeCheckForWithinStackOnly() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(new StackId("HDP-2.2"));
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(new StackId("HDP-2.2"));
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.3.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.3"));
+
+    // false because the upgrade is for 2.2->2.3 and the check is only for 2.2
+    // to 2.2
+    Assert.assertFalse(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+
+  @Test
+  public void testUpgradeCheckMatchesExactly() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(new StackId("HDP-2.2"));
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(new StackId("HDP-2.2"));
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    // pass because the upgrade is for 2.2->2.2 and the check is only for 2.2
+    // to 2.2
+    Assert.assertTrue(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+
+  @Test
+  public void testNoUpgradeStacksDefined() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(null);
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(null);
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.3.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.3"));
+
+    // pass because there are no restrictions
+    Assert.assertTrue(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+
+  @Test
+  public void testUpgradeStartsAtSpecifiedStackVersion() throws Exception {
+    AbstractCheckDescriptor invalidCheck = EasyMock.createMockBuilder(AbstractCheckDescriptor.class).addMockedMethods(
+        "getSourceStack", "getTargetStack").createMock();
+
+    EasyMock.expect(invalidCheck.getSourceStack()).andReturn(new StackId("HDP-2.3")).atLeastOnce();
+    EasyMock.expect(invalidCheck.getTargetStack()).andReturn(null).atLeastOnce();
+
+    EasyMock.replay(invalidCheck);
+
+    PrereqCheckRequest checkRequest = new PrereqCheckRequest("c1");
+    checkRequest.setRepositoryVersion("HDP-2.2.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.2"));
+
+    // false because this check starts at 2.3 and the upgrade is 2.2 -> 2.2
+    Assert.assertFalse(invalidCheck.isApplicable(checkRequest));
+
+    checkRequest.setRepositoryVersion("HDP-2.3.0.0");
+    checkRequest.setSourceStackId(new StackId("HDP", "2.2"));
+    checkRequest.setTargetStackId(new StackId("HDP", "2.3"));
+
+    // false because this check starts at 2.3 and the upgrade is 2.2 -> 2.3
+    Assert.assertFalse(invalidCheck.isApplicable(checkRequest));
+
+    EasyMock.verify(invalidCheck);
+  }
+}