You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/10/03 20:15:52 UTC

[05/22] ambari git commit: AMBARI-22105 - Upgrades Do Not Finalize If Other Host Versions Are Out of Sync (jonathanhurley)

AMBARI-22105 - Upgrades Do Not Finalize If Other Host Versions Are Out of Sync (jonathanhurley)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 6d51e01f48d5a588c41b47a15c88fe100d2dbf58
Parents: 6062014
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Sun Oct 1 19:41:50 2017 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Oct 2 14:56:12 2017 -0400

----------------------------------------------------------------------
 .../upgrade/HostVersionOutOfSyncListener.java   |   4 +
 .../orm/entities/RepositoryVersionEntity.java   |  34 ++---
 .../org/apache/ambari/server/state/Host.java    |  17 +++
 .../ambari/server/state/host/HostImpl.java      |  43 +++++++
 .../svccomphost/ServiceComponentHostImpl.java   |   9 +-
 .../ServiceComponentHostSummary.java            | 123 -------------------
 .../upgrade/StackVersionListenerTest.java       |   1 -
 .../apache/ambari/server/orm/OrmTestHelper.java |   2 +-
 .../svccomphost/ServiceComponentHostTest.java   | 102 ++++++++++++++-
 9 files changed, 185 insertions(+), 150 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListener.java
index d4c79db..0be036e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListener.java
@@ -301,6 +301,10 @@ public class HostVersionOutOfSyncListener {
           missingHostVersion.getRepositoryVersion().getVersion(), missingHostVersion.getRepositoryVersion().getId());
 
         hostVersionDAO.get().create(missingHostVersion);
+        hostDAO.get().merge(hostEntity);
+
+        hostEntity.getHostVersionEntities().add(missingHostVersion);
+        hostEntity = hostDAO.get().merge(hostEntity);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
index 2b56b11..b4f59dc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
@@ -52,7 +52,6 @@ import org.apache.ambari.server.state.repository.Release;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.EqualsBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -378,26 +377,31 @@ public class RepositoryVersionEntity {
    * {@inheritDoc}
    */
   @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-
-    RepositoryVersionEntity that = (RepositoryVersionEntity) o;
-    return new EqualsBuilder().append(id, that.id).append(stack, that.stack).append(version,
-        that.version).append(displayName, that.displayName).isEquals();
+  public int hashCode() {
+    return java.util.Objects.hash(stack, version, displayName, operatingSystems);
   }
 
   /**
    * {@inheritDoc}
    */
   @Override
-  public int hashCode() {
-    return Objects.hashCode(id, stack, version, displayName);
+  public boolean equals(Object object) {
+    if (null == object) {
+      return false;
+    }
+
+    if (this == object) {
+      return true;
+    }
+
+    if (object.getClass() != getClass()) {
+      return false;
+    }
+
+    RepositoryVersionEntity that = (RepositoryVersionEntity) object;
+    return Objects.equal(stack, that.stack) && Objects.equal(version, that.version)
+        && Objects.equal(displayName, that.displayName)
+        && Objects.equal(operatingSystems, that.operatingSystems);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
index 7f0be86..3a78824 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java
@@ -29,6 +29,7 @@ import org.apache.ambari.server.agent.RecoveryReport;
 import org.apache.ambari.server.controller.HostResponse;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 
 public interface Host extends Comparable {
@@ -407,4 +408,20 @@ public interface Host extends Comparable {
    * @see ComponentInfo#isVersionAdvertised()
    */
   boolean hasComponentsAdvertisingVersions(StackId stackId) throws AmbariException;
+
+  /**
+   * Gets whether all host components whose desired repository version matches
+   * the repository version specified have reported the correct version and are
+   * no longer upgrading.
+   *
+   * @param repositoryVersion
+   *          the repository version to check for (not {@code null}).
+   * @return {@code true} if all components on this host have checked in with
+   *         the correct version if their desired repository matches the one
+   *         specified.
+   *
+   * @throws AmbariException
+   */
+  boolean isRepositoryVersionCorrect(RepositoryVersionEntity repositoryVersion)
+      throws AmbariException;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
index 274a425..4af83ef 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.state.host;
 
 import java.lang.reflect.Type;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -50,6 +51,8 @@ import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostStateEntity;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -65,6 +68,7 @@ import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.UpgradeState;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.SingleArcTransition;
@@ -1168,6 +1172,45 @@ public class HostImpl implements Host {
 
     return false;
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isRepositoryVersionCorrect(RepositoryVersionEntity repositoryVersion)
+      throws AmbariException {
+    HostEntity hostEntity = getHostEntity();
+    Collection<HostComponentStateEntity> hostComponentStates = hostEntity.getHostComponentStateEntities();
+
+    // for every host component, if it matches the desired repo and has reported
+    // the correct version then we're good
+    for (HostComponentStateEntity hostComponentState : hostComponentStates) {
+      ServiceComponentDesiredStateEntity desiredComponmentState = hostComponentState.getServiceComponentDesiredStateEntity();
+      RepositoryVersionEntity desiredRepositoryVersion = desiredComponmentState.getDesiredRepositoryVersion();
+
+      ComponentInfo componentInfo = ambariMetaInfo.getComponent(
+          desiredRepositoryVersion.getStackName(), desiredRepositoryVersion.getStackVersion(),
+          hostComponentState.getServiceName(), hostComponentState.getComponentName());
+
+      // skip components which don't advertise a version
+      if (!componentInfo.isVersionAdvertised()) {
+        continue;
+      }
+
+      // we only care about checking the specified repo version for this host
+      if (!repositoryVersion.equals(desiredRepositoryVersion)) {
+        continue;
+      }
+
+      String versionAdvertised = hostComponentState.getVersion();
+      if (hostComponentState.getUpgradeState() == UpgradeState.IN_PROGRESS
+          || !StringUtils.equals(versionAdvertised, repositoryVersion.getVersion())) {
+        return false;
+      }
+    }
+
+    return true;
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index 230b031..f490ff0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -1440,8 +1440,8 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   @Override
   @Transactional
   public HostVersionEntity recalculateHostVersionState() throws AmbariException {
-    RepositoryVersionEntity repositoryVersion = serviceComponent.getDesiredRepositoryVersion();
     HostEntity hostEntity = host.getHostEntity();
+    RepositoryVersionEntity repositoryVersion = serviceComponent.getDesiredRepositoryVersion();
     HostVersionEntity hostVersionEntity = hostVersionDAO.findHostVersionByHostAndRepository(
         hostEntity, repositoryVersion);
 
@@ -1462,11 +1462,8 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
         hostVersionDAO.create(hostVersionEntity);
       }
 
-      final ServiceComponentHostSummary hostSummary = new ServiceComponentHostSummary(
-          ambariMetaInfo, hostEntity, repositoryVersion);
-
-      if (hostSummary.isVersionCorrectForAllHosts(repositoryVersion)) {
-        if (hostVersionEntity.getState() != RepositoryVersionState.CURRENT) {
+      if (hostVersionEntity.getState() != RepositoryVersionState.CURRENT) {
+        if (host.isRepositoryVersionCorrect(repositoryVersion)) {
           hostVersionEntity.setState(RepositoryVersionState.CURRENT);
           hostVersionEntity = hostVersionDAO.merge(hostVersionEntity);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostSummary.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostSummary.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostSummary.java
deleted file mode 100644
index e9359ef..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostSummary.java
+++ /dev/null
@@ -1,123 +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.svccomphost;
-
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
-import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
-import org.apache.ambari.server.orm.entities.HostEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
-import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
-import org.apache.ambari.server.state.ComponentInfo;
-import org.apache.ambari.server.state.State;
-import org.apache.ambari.server.state.UpgradeState;
-import org.apache.commons.lang.StringUtils;
-
-
-/**
- * Represents a summary of the versions of the components installed on a host.
- */
-public class ServiceComponentHostSummary {
-
-  private Collection<HostComponentStateEntity> allHostComponents;
-  private Collection<HostComponentStateEntity> haveAdvertisedVersion;
-  private Collection<HostComponentStateEntity> waitingToAdvertiseVersion;
-  private Collection<HostComponentStateEntity> noVersionToAdvertise;
-
-  /**
-   * Constructor.
-   *
-   * @param ambariMetaInfo
-   *          used to lookup whether a component advertises a version (not
-   *          {@code null}).
-   * @param host
-   *          the host to generate a component summary for (not {@code null}).
-   * @param repositoryVersion
-   *          the repository to generate a summary for (not {@code null}).
-   * @throws AmbariException
-   */
-  public ServiceComponentHostSummary(AmbariMetaInfo ambariMetaInfo, HostEntity host,
-      RepositoryVersionEntity repositoryVersion) throws AmbariException {
-    allHostComponents = host.getHostComponentStateEntities();
-    haveAdvertisedVersion = new HashSet<>();
-    waitingToAdvertiseVersion = new HashSet<>();
-    noVersionToAdvertise = new HashSet<>();
-
-    String stackName = repositoryVersion.getStackName();
-    String stackVersion = repositoryVersion.getStackVersion();
-
-    for (HostComponentStateEntity hostComponentStateEntity : allHostComponents) {
-      ComponentInfo compInfo = ambariMetaInfo.getComponent(
-          stackName, stackVersion, hostComponentStateEntity.getServiceName(),
-          hostComponentStateEntity.getComponentName());
-
-      if (!compInfo.isVersionAdvertised()) {
-        // Some Components cannot advertise a version. E.g., ZKF, AMBARI_METRICS, Kerberos
-        noVersionToAdvertise.add(hostComponentStateEntity);
-        continue;
-      }
-
-      String versionAdvertised = hostComponentStateEntity.getVersion();
-      if (hostComponentStateEntity.getUpgradeState() == UpgradeState.IN_PROGRESS
-          || StringUtils.equals(versionAdvertised, State.UNKNOWN.name())) {
-        waitingToAdvertiseVersion.add(hostComponentStateEntity);
-        continue;
-      }
-
-      haveAdvertisedVersion.add(hostComponentStateEntity);
-    }
-  }
-
-  /**
-   * Gets whether all hosts for a service component have reported the correct
-   * version.
-   *
-   * @param repositoryVersion
-   *          the version to report (not {@code null}).
-   * @return {@code true} if all hosts for this service component have reported
-   *         the correct version, {@code false} othwerise.
-   */
-  public boolean isVersionCorrectForAllHosts(RepositoryVersionEntity repositoryVersion) {
-    if (!waitingToAdvertiseVersion.isEmpty()) {
-      return false;
-    }
-
-    for (HostComponentStateEntity hostComponent : haveAdvertisedVersion) {
-      if (UpgradeState.VERSION_NON_ADVERTISED_STATES.contains(hostComponent.getUpgradeState())) {
-        return false;
-      }
-
-      ServiceComponentDesiredStateEntity desiredState = hostComponent.getServiceComponentDesiredStateEntity();
-      RepositoryVersionEntity desiredRepositoryVersion = desiredState.getDesiredRepositoryVersion();
-      if (!desiredRepositoryVersion.equals(repositoryVersion)) {
-        continue;
-      }
-
-      if (!StringUtils.equals(hostComponent.getVersion(), desiredRepositoryVersion.getVersion())) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
index 5e12cdf..7387867 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
@@ -62,7 +62,6 @@ public class StackVersionListenerTest extends EasyMockSupport {
   private static final Long CLUSTER_ID = 1L;
   private static final String UNKNOWN_VERSION = "UNKNOWN";
   private static final String VALID_PREVIOUS_VERSION = "2.2.0.0";
-  private static final RepositoryVersionEntity DUMMY_REPOSITORY_VERSION_ENTITY = new RepositoryVersionEntity();
   private static final HostVersionEntity DUMMY_HOST_VERSION_ENTITY = new HostVersionEntity();
   private static final UpgradeEntity DUMMY_UPGRADE_ENTITY = new UpgradeEntity();
   public static final String STACK_NAME = "HDP";

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index 2c6c096..bd8be3b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -674,7 +674,7 @@ public class OrmTestHelper {
             String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), "");
       } catch (Exception ex) {
         LOG.error("Caught exception", ex);
-        ex.printStackTrace();
+
         Assert.fail(MessageFormat.format("Unable to create Repo Version for Stack {0} and version {1}",
             stackEntity.getStackName() + "-" + stackEntity.getStackVersion(), version));
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6d51e01f/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index a989738..48864cc 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.state.svccomphost;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -41,7 +42,9 @@ import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
+import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.HostVersionEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -50,6 +53,7 @@ import org.apache.ambari.server.state.ConfigFactory;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostConfig;
 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;
 import org.apache.ambari.server.state.ServiceComponentFactory;
@@ -60,9 +64,12 @@ import org.apache.ambari.server.state.ServiceComponentHostFactory;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.UpgradeState;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
+import org.apache.ambari.server.utils.EventBusSynchronizer;
+import org.apache.commons.lang3.StringUtils;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -114,16 +121,19 @@ public class ServiceComponentHostTest {
     injector.getInstance(GuiceJpaInitializer.class);
     injector.injectMembers(this);
 
+    EventBusSynchronizer.synchronizeAmbariEventPublisher(injector);
+
     StackId stackId = new StackId("HDP-2.0.6");
     createCluster(stackId, clusterName);
+
+    repositoryVersion = helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
+
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "5.9");
-
     Set<String> hostNames = new HashSet<>();
     hostNames.add(hostName1);
-    addHostsToCluster(clusterName, hostAttributes, hostNames);
 
-    repositoryVersion = helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
+    addHostsToCluster(clusterName, hostAttributes, hostNames);
   }
 
   @After
@@ -1050,4 +1060,88 @@ public class ServiceComponentHostTest {
     );
     Assert.assertEquals(MaintenanceState.ON, entity.getMaintenanceState());
   }
-}
+
+  /**
+   * Tests that the host version for a repository can transition properly to
+   * CURRENT even if other components on that host have not reported in correct
+   * for their own repo versions. This assures that the host version logic is
+   * scoped to the repo that is transitioning and is not affected by other
+   * components.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testHostVersionTransitionIsScopedByRepository() throws Exception {
+    // put the existing host versions OUT_OF_SYNC
+    HostEntity hostEntity = hostDAO.findByName(hostName1);
+    Collection<HostVersionEntity> hostVersions = hostEntity.getHostVersionEntities();
+    Assert.assertEquals(1, hostVersions.size());
+    hostVersions.iterator().next().setState(RepositoryVersionState.OUT_OF_SYNC);
+    hostDAO.merge(hostEntity);
+
+    ServiceComponentHost namenode = createNewServiceComponentHost(clusterName, "HDFS", "NAMENODE", hostName1, false);
+    namenode.setDesiredState(State.STARTED);
+    namenode.setState(State.STARTED);
+
+    ServiceComponentHost datanode = createNewServiceComponentHost(clusterName, "HDFS", "DATANODE", hostName1, false);
+    datanode.setDesiredState(State.STARTED);
+    datanode.setState(State.STARTED);
+
+    ServiceComponentHost zkServer = createNewServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_SERVER", hostName1, false);
+    zkServer.setDesiredState(State.STARTED);
+    zkServer.setState(State.STARTED);
+
+    ServiceComponentHost zkClient = createNewServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostName1, true);
+    zkClient.setDesiredState(State.STARTED);
+    zkClient.setState(State.STARTED);
+
+    // put some host components into a bad state
+    hostEntity = hostDAO.findByName(hostName1);
+    Collection<HostComponentStateEntity> hostComponentStates = hostEntity.getHostComponentStateEntities();
+    for( HostComponentStateEntity hostComponentState : hostComponentStates ) {
+      if( StringUtils.equals("HDFS", hostComponentState.getServiceName() ) ) {
+        hostComponentState.setVersion(State.UNKNOWN.name());
+        hostComponentStateDAO.merge(hostComponentState);
+      }
+    }
+
+    // create the repo just for ZK
+    StackId stackId = new StackId("HDP-2.2.0");
+    RepositoryVersionEntity patchRepositoryVersion = helper.getOrCreateRepositoryVersion(stackId, "2.2.0.0-1");
+
+    // create the new host version
+    zkServer.getServiceComponent().setDesiredRepositoryVersion(patchRepositoryVersion);
+    zkClient.getServiceComponent().setDesiredRepositoryVersion(patchRepositoryVersion);
+
+    helper.createHostVersion(hostName1, patchRepositoryVersion, RepositoryVersionState.INSTALLED);
+
+    // move ZK components to UPGRADED and reporting the new version
+    hostEntity = hostDAO.findByName(hostName1);
+    hostComponentStates = hostEntity.getHostComponentStateEntities();
+    for( HostComponentStateEntity hostComponentState : hostComponentStates ) {
+      if( StringUtils.equals("ZOOKEEPER", hostComponentState.getServiceName() ) ) {
+        hostComponentState.setVersion(patchRepositoryVersion.getVersion());
+        hostComponentState.setUpgradeState(UpgradeState.COMPLETE);
+        hostComponentStateDAO.merge(hostComponentState);
+      }
+    }
+
+    hostEntity = hostDAO.merge(hostEntity);
+
+    zkServer.recalculateHostVersionState();
+
+    // very transition to CURRENT
+    hostVersions = hostEntity.getHostVersionEntities();
+    Assert.assertEquals(2, hostVersions.size());
+
+    for (HostVersionEntity hostVersion : hostVersions) {
+      if (hostVersion.getRepositoryVersion().equals(repositoryVersion)) {
+        Assert.assertEquals(RepositoryVersionState.OUT_OF_SYNC, hostVersion.getState());
+      } else if (hostVersion.getRepositoryVersion().equals(patchRepositoryVersion)) {
+        Assert.assertEquals(RepositoryVersionState.CURRENT, hostVersion.getState());
+      } else {
+        Assert.fail("Unexpected repository version");
+      }
+    }
+  }
+}
\ No newline at end of file