You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/10/02 17:58:49 UTC

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

Repository: ambari
Updated Branches:
  refs/heads/branch-2.6 53d37ebee -> e58ceff72


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/e58ceff7
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e58ceff7
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e58ceff7

Branch: refs/heads/branch-2.6
Commit: e58ceff7288a49f55a9f647fa0f05e9d500f4882
Parents: 53d37eb
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 13:58:39 2017 -0400

----------------------------------------------------------------------
 .../upgrade/HostVersionOutOfSyncListener.java   |   4 +
 .../orm/entities/RepositoryVersionEntity.java   |  65 +++++-----
 .../org/apache/ambari/server/state/Host.java    |  17 +++
 .../ambari/server/state/host/HostImpl.java      |  44 ++++++-
 .../svccomphost/ServiceComponentHostImpl.java   |   9 +-
 .../ServiceComponentHostSummary.java            | 123 -------------------
 .../upgrade/StackVersionListenerTest.java       |   1 -
 .../apache/ambari/server/orm/OrmTestHelper.java |   2 +-
 .../svccomphost/ServiceComponentHostTest.java   |  99 ++++++++++++++-
 9 files changed, 192 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e58ceff7/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 2eb89a2..7874461 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/e58ceff7/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 072863d..a3b963b 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
@@ -313,37 +313,6 @@ public class RepositoryVersionEntity {
     this.type = type;
   }
 
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-
-    RepositoryVersionEntity that = (RepositoryVersionEntity) o;
-
-    if (id != null ? !id.equals(that.id) : that.id != null) {
-      return false;
-    }
-    if (stack != null ? !stack.equals(that.stack) : that.stack != null) {
-      return false;
-    }
-    if (version != null ? !version.equals(that.version) : that.version != null) {
-      return false;
-    }
-    if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) {
-      return false;
-    }
-
-    if (operatingSystems != null ? !operatingSystems.equals(that.operatingSystems) : that.operatingSystems != null) {
-      return false;
-    }
-
-    return true;
-  }
-
   /**
    * @return the XML that is the basis for the version
    */
@@ -404,14 +373,36 @@ public class RepositoryVersionEntity {
     return versionDefinition;
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
   public int hashCode() {
-    int result = id != null ? id.hashCode() : 0;
-    result = 31 * result + (stack != null ? stack.hashCode() : 0);
-    result = 31 * result + (version != null ? version.hashCode() : 0);
-    result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
-    result = 31 * result + (operatingSystems != null ? operatingSystems.hashCode() : 0);
-    return result;
+    return java.util.Objects.hash(stack, version, displayName, operatingSystems);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  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/e58ceff7/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 78587af..13196ac 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 {
@@ -409,4 +410,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/e58ceff7/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 cca27d2..794680a 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,13 +18,13 @@
 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;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -52,6 +52,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;
@@ -67,6 +69,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;
@@ -1187,6 +1190,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/e58ceff7/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 f9d3cfc..68bcf1d 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
@@ -1500,8 +1500,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);
 
@@ -1522,11 +1522,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/e58ceff7/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/e58ceff7/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 3ea76cb..fdd75c5 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/e58ceff7/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 ad95803..c905a42 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/e58ceff7/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 3aad5b0..7fc99c9 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;
@@ -43,6 +44,7 @@ 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;
@@ -51,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.SecurityState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -62,9 +65,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;
@@ -116,16 +122,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
@@ -1102,4 +1111,88 @@ public class ServiceComponentHostTest {
       }
     }
   }
+
+  /**
+   * 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