ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jonathanhur...@apache.org
Subject [1/2] ambari git commit: AMBARI-12889 - Distribute Repository For Upgrade With Unhealthy Hosts (jonathanhurley)
Date Thu, 27 Aug 2015 20:36:27 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk a71c52838 -> 59dd207c3


AMBARI-12889 - Distribute Repository For Upgrade With Unhealthy Hosts (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 3b5efe48706f34ad5f89290d45ae16980237d5ce
Parents: a71c528
Author: Jonathan Hurley <jhurley@hortonworks.com>
Authored: Wed Aug 26 17:10:45 2015 -0400
Committer: Jonathan Hurley <jhurley@hortonworks.com>
Committed: Thu Aug 27 15:22:57 2015 -0400

----------------------------------------------------------------------
 .../ClusterStackVersionResourceProvider.java    | 74 ++++++++++++++------
 .../org/apache/ambari/server/state/Cluster.java | 24 +++++--
 .../server/state/cluster/ClusterImpl.java       | 42 +++++------
 ...ClusterStackVersionResourceProviderTest.java | 10 ++-
 .../server/state/cluster/ClusterTest.java       | 71 +++++++++++++++++--
 5 files changed, 164 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3b5efe48/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
index 2f3e959..a942c93 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -69,8 +70,10 @@ import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceInfo;
@@ -300,17 +303,19 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
     desiredRepoVersion = (String) propertyMap.get(CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID);
 
     Cluster cluster;
-    Map<String, Host> hostsForCluster;
-
     AmbariManagementController managementController = getManagementController();
     AmbariMetaInfo ami = managementController.getAmbariMetaInfo();
+
     try {
-      cluster = managementController.getClusters().getCluster(clName);
-      hostsForCluster = managementController.getClusters().getHostsForCluster(clName);
+      Clusters clusters = managementController.getClusters();
+      cluster = clusters.getCluster(clName);
     } catch (AmbariException e) {
       throw new NoSuchParentResourceException(e.getMessage(), e);
     }
 
+    // get all of the host eligible for stack distribution
+    List<Host> hosts = getHostsForStackDistribution(cluster);
+
     final StackId stackId;
     if (propertyMap.containsKey(CLUSTER_STACK_VERSION_STACK_PROPERTY_ID) &&
             propertyMap.containsKey(CLUSTER_STACK_VERSION_VERSION_PROPERTY_ID)) {
@@ -350,13 +355,13 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
 
     RequestStageContainer req = createRequest();
 
-    Iterator<Host> hostsForClusterIter = hostsForCluster.values().iterator();
+    Iterator<Host> hostIterator = hosts.iterator();
     Map<String, String> hostLevelParams = new HashMap<String, String>();
     hostLevelParams.put(JDK_LOCATION, getManagementController().getJdkResourceUrl());
     String hostParamsJson = StageUtils.getGson().toJson(hostLevelParams);
 
     int maxTasks = configuration.getAgentPackageParallelCommandsLimit();
-    int hostCount = hostsForCluster.size();
+    int hostCount = hosts.size();
     int batchCount = (int) (Math.ceil((double)hostCount / maxTasks));
 
     ArrayList<Host> directTransitions = new ArrayList<Host>();
@@ -394,8 +399,8 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
       stages.add(stage);
 
       // Populate with commands for host
-      for (int i = 0; i < maxTasks && hostsForClusterIter.hasNext(); i++) {
-        Host host = hostsForClusterIter.next();
+      for (int i = 0; i < maxTasks && hostIterator.hasNext(); i++) {
+        Host host = hostIterator.next();
         if (hostHasVersionableComponents(cluster, ami, stackId, host)) {
           addHostVersionInstallCommandsToStage(desiredRepoVersion,
                   cluster, managementController, ami, stackId, perOsRepos, stage, host);
@@ -405,19 +410,21 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
 
       }
     }
+
     req.addStages(stages);
 
     try {
-      ClusterVersionEntity existingCSVer = clusterVersionDAO.findByClusterAndStackAndVersion(
+      ClusterVersionEntity clusterVersionEntity = clusterVersionDAO.findByClusterAndStackAndVersion(
           clName, stackId, desiredRepoVersion);
 
-      if (existingCSVer == null) {
+      if (clusterVersionEntity == null) {
         try {
           // Create/persist new cluster stack version
           cluster.createClusterVersion(stackId,
               desiredRepoVersion, managementController.getAuthName(),
               RepositoryVersionState.INSTALLING);
-          existingCSVer = clusterVersionDAO.findByClusterAndStackAndVersion(
+
+          clusterVersionEntity = clusterVersionDAO.findByClusterAndStackAndVersion(
               clName, stackId, desiredRepoVersion);
         } catch (AmbariException e) {
           throw new SystemException(
@@ -432,12 +439,13 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
       }
 
       // Will also initialize all Host Versions in an INSTALLING state.
-      cluster.inferHostVersions(existingCSVer);
+      cluster.transitionHostsToInstalling(clusterVersionEntity);
 
       // Directly transition host versions to INSTALLED for hosts that don't have
       // versionable components
       for(Host host : directTransitions) {
-        transitionHostVersionToInstalled(host, cluster, existingCSVer.getRepositoryVersion().getVersion());
+        transitionHostVersionToInstalled(host, cluster,
+            clusterVersionEntity.getRepositoryVersion().getVersion());
       }
 
       req.persist();
@@ -449,11 +457,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
   }
 
   private void addHostVersionInstallCommandsToStage(final String desiredRepoVersion,
-                                                    Cluster cluster, AmbariManagementController
managementController,
-                                                    AmbariMetaInfo ami,
-                                                    final StackId stackId,
-                                                    Map<String, List<RepositoryEntity>>
perOsRepos,
-                                                    Stage stage, Host host) throws SystemException
{
+      Cluster cluster, AmbariManagementController managementController, AmbariMetaInfo ami,
+      final StackId stackId, Map<String, List<RepositoryEntity>> perOsRepos,
Stage stage, Host host)
+          throws SystemException {
     // Determine repositories for host
     final List<RepositoryEntity> repoInfo = perOsRepos.get(host.getOsFamily());
     if (repoInfo == null) {
@@ -461,6 +467,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
                       "not defined. Repo version=%s, stackId=%s",
               host.getOsFamily(), desiredRepoVersion, stackId));
     }
+
     // determine packages for all services that are installed on host
     List<ServiceOsSpecific.Package> packages = new ArrayList<ServiceOsSpecific.Package>();
     Set<String> servicesOnHost = new HashSet<String>();
@@ -486,6 +493,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
         }
       }
     }
+
     final String packageList = gson.toJson(packages);
     final String repoList = gson.toJson(repoInfo);
 
@@ -517,8 +525,8 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
    * Returns true if there is at least one versionable component on host for a given
    * stack.
    */
-  private boolean hostHasVersionableComponents(Cluster cluster, AmbariMetaInfo ami,
-                                               StackId stackId, Host host) throws SystemException
{
+  private boolean hostHasVersionableComponents(Cluster cluster, AmbariMetaInfo ami, StackId
stackId,
+      Host host) throws SystemException {
     List<ServiceComponentHost> components = cluster.getServiceComponentHosts(host.getHostName());
     for (ServiceComponentHost component : components) {
       ComponentInfo componentInfo;
@@ -543,8 +551,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
    *  Transitioning host version to INSTALLED state manually would not be the
    *  best idea since some additional logic may be bound to event listeners.
    */
-  private void transitionHostVersionToInstalled(Host host, Cluster cluster,
-                                                String version) {
+  private void transitionHostVersionToInstalled(Host host, Cluster cluster, String version)
{
     LOG.info(String.format("Transitioning version %s on host %s directly to installed" +
                     " without distributing bits to host since it has no versionable components.",
             version, host.getHostName()));
@@ -691,4 +698,27 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
   protected Set<String> getPKPropertyIds() {
     return pkPropertyIds;
   }
+
+  /**
+   * Gets all of the hosts in a cluster which are not in "maintenance mode" and
+   * are considered to be healthy. In the case of stack distribution, a host
+   * must be explicitely marked as being in maintenance mode for it to be
+   * considered as unhealthy.
+   *
+   * @param cluster
+   *          the cluster (not {@code null}).
+   * @return the list of hosts that are not in maintenance mode and are
+   *         elidgable to have a stack distributed to them.
+   */
+  private List<Host> getHostsForStackDistribution(Cluster cluster) {
+    Collection<Host> hosts = cluster.getHosts();
+    List<Host> healthyHosts = new ArrayList<>(hosts.size());
+    for (Host host : hosts) {
+      if (host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.OFF) {
+        healthyHosts.add(host);
+      }
+    }
+
+    return healthyHosts;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b5efe48/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index ad481f3..5209dfb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -180,15 +180,25 @@ public interface Cluster {
       RepositoryVersionState desiredState) throws AmbariException;
 
   /**
-   * Create/update host versions for all of the hosts within a cluster based on state of
cluster stack version.
-   * The difference of this method compared to {@link Cluster#mapHostVersions}
-   * is that it affects all hosts (not only missing hosts). Also, current method contains
some additional logics to allow only INSTALLING
-   * state for hosts.
-   * @param sourceClusterVersion cluster version to be queried for a stack name/version info
and desired RepositoryVersionState. The only valid state
-   * of a cluster version is {@link RepositoryVersionState#INSTALLING}
+   * Creates or updates host versions for all of the hosts within a cluster
+   * based on state of cluster stack version. This is used to transition all
+   * hosts into the {@link RepositoryVersionState#INSTALLING} state.
+   * <p/>
+   * The difference between this method compared to
+   * {@link Cluster#mapHostVersions} is that it affects all hosts (not only
+   * missing hosts).
+   * <p/>
+   * Hosts that are in maintenance mode will not be included. These hosts have
+   * been explicitely marked as being in maintenance andd are not included in
+   * this operation.
+   *
+   * @param sourceClusterVersion
+   *          cluster version to be queried for a stack name/version info and
+   *          desired RepositoryVersionState. The only valid state of a cluster
+   *          version is {@link RepositoryVersionState#INSTALLING}
    * @throws AmbariException
    */
-  void inferHostVersions(ClusterVersionEntity sourceClusterVersion)
+  void transitionHostsToInstalling(ClusterVersionEntity sourceClusterVersion)
       throws AmbariException;
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b5efe48/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 86f5f32..4fe24e9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -1133,27 +1133,18 @@ public class ClusterImpl implements Cluster {
   }
 
   /**
-   * Because this is a top-down approach, it should only be called for the purposes of bootstrapping
data, such as
-   * installing a brand new cluster (through Blueprints).
-   * @param sourceClusterVersion cluster version to be queried for a stack name/version info
and desired RepositoryVersionState.
-   * The only valid state of this cluster version is {@link RepositoryVersionState#INSTALLING}
-   * @throws AmbariException
+   * {@inheritDoc}
    */
   @Override
-  public void inferHostVersions(ClusterVersionEntity sourceClusterVersion) throws AmbariException
{
+  public void transitionHostsToInstalling(ClusterVersionEntity sourceClusterVersion) throws
AmbariException {
     if (sourceClusterVersion == null) {
       throw new AmbariException("Could not find current stack version of cluster " + getClusterName());
     }
 
-    RepositoryVersionState desiredState = sourceClusterVersion.getState();
-
-    @SuppressWarnings("serial")
-    Set<RepositoryVersionState> validStates = new HashSet<RepositoryVersionState>(){{
-      add(RepositoryVersionState.INSTALLING);
-    }};
-
-    if (!validStates.contains(desiredState)) {
-      throw new AmbariException("The state must be one of " + validStates);
+    if (RepositoryVersionState.INSTALLING != sourceClusterVersion.getState()) {
+      throw new AmbariException("Unable to transition cluster hosts into "
+          + RepositoryVersionState.INSTALLING
+          + ". The only valid state is INSTALLING");
     }
 
     Map<String, Host> hosts = clusters.getHostsForCluster(getClusterName());
@@ -1169,17 +1160,26 @@ public class ClusterImpl implements Cluster {
           getClusterName(), repoVersionStackId,
           sourceClusterVersion.getRepositoryVersion().getVersion());
 
-      if (existingHostVersionEntities != null) {
-        for (HostVersionEntity entity : existingHostVersionEntities) {
-          existingHostsWithClusterStackAndVersion.add(entity.getHostName());
-          existingHostStackVersions.put(entity.getHostName(), entity);
-        }
+      // for each host that already has a stack and version, keep track of them
+      for (HostVersionEntity entity : existingHostVersionEntities) {
+        String hostName = entity.getHostName();
+        existingHostsWithClusterStackAndVersion.add(hostName);
+        existingHostStackVersions.put(hostName, entity);
       }
 
+      // find any hosts that do not have the stack/repo version already
       Sets.SetView<String> hostsMissingRepoVersion = Sets.difference(
           hosts.keySet(), existingHostsWithClusterStackAndVersion);
 
       for (String hostname : hosts.keySet()) {
+        // if the host is in maintenance mode, that's an explicit marker which
+        // indicates that it should not be transitioned to INSTALLING; these
+        // hosts are excluded from being transitioned into INSTALLING
+        Host host = hosts.get(hostname);
+        if (host.getMaintenanceState(getClusterId()) != MaintenanceState.OFF) {
+          continue;
+        }
+
         if (hostsMissingRepoVersion.contains(hostname)) {
           // Create new host stack version
           HostEntity hostEntity = hostDAO.findByName(hostname);
@@ -1190,7 +1190,7 @@ public class ClusterImpl implements Cluster {
         } else {
           // Update existing host stack version
           HostVersionEntity hostVersionEntity = existingHostStackVersions.get(hostname);
-          hostVersionEntity.setState(desiredState);
+          hostVersionEntity.setState(RepositoryVersionState.INSTALLING);
           hostVersionDAO.merge(hostVersionEntity);
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b5efe48/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
index 5b24edc..1819ef9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
@@ -78,6 +78,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceInfo;
@@ -181,6 +182,9 @@ public class ClusterStackVersionResourceProviderTest {
       Host host = createNiceMock(hostname, Host.class);
       expect(host.getHostName()).andReturn(hostname).anyTimes();
       expect(host.getOsFamily()).andReturn("redhat6").anyTimes();
+      expect(host.getMaintenanceState(EasyMock.anyLong())).andReturn(
+          MaintenanceState.OFF).anyTimes();
+
       replay(host);
       hostsForCluster.put(hostname, host);
     }
@@ -238,10 +242,12 @@ public class ClusterStackVersionResourceProviderTest {
             eq(managementController))).andReturn(csvResourceProvider).anyTimes();
 
     expect(clusters.getCluster(anyObject(String.class))).andReturn(cluster);
-    expect(clusters.getHostsForCluster(anyObject(String.class))).andReturn(hostsForCluster);
+    expect(clusters.getHostsForCluster(anyObject(String.class))).andReturn(
+        hostsForCluster).anyTimes();
 
     String clusterName = "Cluster100";
-    //expect(cluster.getClusterName()).andReturn(clusterName).anyTimes();
+    expect(cluster.getClusterId()).andReturn(1L).anyTimes();
+    expect(cluster.getHosts()).andReturn(hostsForCluster.values()).atLeastOnce();
     expect(cluster.getCurrentStackVersion()).andReturn(stackId);
     expect(cluster.getServiceComponentHosts(anyObject(String.class))).andAnswer(new IAnswer<List<ServiceComponentHost>>()
{
       @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b5efe48/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
index f047b33..edd6267 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
@@ -42,8 +42,6 @@ import java.util.Set;
 import javax.persistence.EntityManager;
 import javax.persistence.RollbackException;
 
-import junit.framework.Assert;
-
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.AgentEnv;
 import org.apache.ambari.server.agent.AgentEnv.Directory;
@@ -88,6 +86,7 @@ import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -117,6 +116,8 @@ import com.google.inject.persist.Transactional;
 import com.google.inject.persist.UnitOfWork;
 import com.google.inject.util.Modules;
 
+import junit.framework.Assert;
+
 public class ClusterTest {
 
   private Clusters clusters;
@@ -1423,14 +1424,24 @@ public class ClusterTest {
     assertNotNull(c1.getCurrentClusterVersion());
   }
 
+  /**
+   * Tests that hosts can be correctly transitioned into the "INSTALLING" state.
+   * This method also tests that hosts in MM will not be transitioned, as per
+   * the contract of
+   * {@link Cluster#transitionHostsToInstalling(ClusterVersionEntity)}.
+   *
+   * @throws Exception
+   */
   @Test
-  public void testInferHostVersions() throws Exception {
+  public void testTransitionHostVersions() throws Exception {
     createDefaultCluster();
 
     StackId stackId = new StackId("HDP", "0.2");
     helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
+
     c1.createClusterVersion(stackId, "0.2", "admin",
         RepositoryVersionState.INSTALLING);
+
     ClusterVersionEntity entityHDP2 = null;
     for (ClusterVersionEntity entity : c1.getAllClusterVersions()) {
       StackEntity repoVersionStackEntity = entity.getRepositoryVersion().getStack();
@@ -1442,12 +1453,13 @@ public class ClusterTest {
         break;
       }
     }
+
     assertNotNull(entityHDP2);
 
     List<HostVersionEntity> hostVersionsH1Before = hostVersionDAO.findByClusterAndHost("c1",
"h1");
     assertEquals(1, hostVersionsH1Before.size());
 
-    c1.inferHostVersions(entityHDP2);
+    c1.transitionHostsToInstalling(entityHDP2);
 
     List<HostVersionEntity> hostVersionsH1After = hostVersionDAO.findByClusterAndHost("c1",
"h1");
     assertEquals(2, hostVersionsH1After.size());
@@ -1462,10 +1474,11 @@ public class ClusterTest {
         break;
       }
     }
+
     assertTrue(checked);
 
     // Test for update of existing host stack version
-    c1.inferHostVersions(entityHDP2);
+    c1.transitionHostsToInstalling(entityHDP2);
 
     hostVersionsH1After = hostVersionDAO.findByClusterAndHost("c1", "h1");
     assertEquals(2, hostVersionsH1After.size());
@@ -1480,7 +1493,55 @@ public class ClusterTest {
         break;
       }
     }
+
     assertTrue(checked);
+
+    // reset all to INSTALL_FAILED
+    List<HostVersionEntity> hostVersionEntities = hostVersionDAO.findAll();
+    for (HostVersionEntity hostVersionEntity : hostVersionEntities) {
+      hostVersionEntity.setState(RepositoryVersionState.INSTALL_FAILED);
+      hostVersionDAO.merge(hostVersionEntity);
+    }
+
+    // verify they have been transition to INSTALL_FAILED
+    hostVersionEntities = hostVersionDAO.findAll();
+    for (HostVersionEntity hostVersionEntity : hostVersionEntities) {
+      assertEquals(RepositoryVersionState.INSTALL_FAILED, hostVersionEntity.getState());
+    }
+
+    // put 1 host in maintenance mode
+    Collection<Host> hosts = c1.getHosts();
+    Iterator<Host> iterator = hosts.iterator();
+    Host hostInMaintenanceMode = iterator.next();
+    Host hostNotInMaintenanceMode = iterator.next();
+    hostInMaintenanceMode.setMaintenanceState(c1.getClusterId(), MaintenanceState.ON);
+
+    // transition host versions to INSTALLING
+    c1.transitionHostsToInstalling(entityHDP2);
+
+    List<HostVersionEntity> hostInMaintModeVersions = hostVersionDAO.findByClusterAndHost("c1",
+        hostInMaintenanceMode.getHostName());
+
+    List<HostVersionEntity> otherHostVersions = hostVersionDAO.findByClusterAndHost("c1",
+        hostNotInMaintenanceMode.getHostName());
+
+    // verify the MM host is in INSTALL_FAILED still
+    for (HostVersionEntity hostVersionEntity : hostInMaintModeVersions) {
+      StackEntity repoVersionStackEntity = hostVersionEntity.getRepositoryVersion().getStack();
+      if (repoVersionStackEntity.getStackName().equals("HDP")
+          && repoVersionStackEntity.getStackVersion().equals("0.2")) {
+        assertEquals(RepositoryVersionState.INSTALL_FAILED, hostVersionEntity.getState());
+      }
+    }
+
+    // verify the other host is in INSTALLING
+    for (HostVersionEntity hostVersionEntity : otherHostVersions) {
+      StackEntity repoVersionStackEntity = hostVersionEntity.getRepositoryVersion().getStack();
+      if (repoVersionStackEntity.getStackName().equals("HDP")
+          && repoVersionStackEntity.getStackVersion().equals("0.2")) {
+      assertEquals(RepositoryVersionState.INSTALLING, hostVersionEntity.getState());
+      }
+    }
   }
 
   @Test


Mime
View raw message