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

ambari git commit: AMBARI-9183. Rollling Upgrade - Server bootstrap creates incorrect repo version (Yurii Shylov via ncole)

Repository: ambari
Updated Branches:
  refs/heads/trunk 01fa8eb03 -> fe3f405fa


AMBARI-9183. Rollling Upgrade - Server bootstrap creates incorrect repo version (Yurii Shylov via ncole)


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

Branch: refs/heads/trunk
Commit: fe3f405fadeafec62e2e257a60342fe7ebe52484
Parents: 01fa8eb
Author: Nate Cole <nc...@hortonworks.com>
Authored: Mon Jan 19 15:15:03 2015 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Mon Jan 19 15:15:03 2015 -0500

----------------------------------------------------------------------
 .../ambari/server/agent/HeartBeatHandler.java   |  14 ++-
 .../AmbariManagementControllerImpl.java         |  19 ---
 .../internal/UpgradeResourceProvider.java       |   1 -
 .../ambari/server/orm/dao/HostVersionDAO.java   |  28 +++++
 .../org/apache/ambari/server/state/Cluster.java |   2 +-
 .../server/state/cluster/ClusterImpl.java       | 122 ++++++++++---------
 .../server/state/cluster/ClustersImpl.java      |   1 -
 .../svccomphost/ServiceComponentHostImpl.java   |  72 +++++++++--
 .../server/state/cluster/ClusterTest.java       |   6 +-
 9 files changed, 167 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index b5fda49..929329d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -73,6 +73,7 @@ import org.apache.ambari.server.state.HostHealthStatus;
 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.RepositoryVersionState;
 import org.apache.ambari.server.state.SecurityState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -470,19 +471,22 @@ public class HeartBeatHandler {
 
             // Reading component version if it is present
             if (StringUtils.isNotBlank(report.getStructuredOut())) {
+              ComponentVersionStructuredOut structuredOutput = null;
               try {
-                final ComponentVersionStructuredOut structuredOutput = gson.fromJson(report.getStructuredOut(), ComponentVersionStructuredOut.class);
+                structuredOutput = gson.fromJson(report.getStructuredOut(), ComponentVersionStructuredOut.class);
+              } catch (JsonSyntaxException ex) {
+                //Json structure for component version was incorrect
+                //do nothing, pass this data further for processing
+              }
+              if (structuredOutput != null && StringUtils.isNotBlank(structuredOutput.getVersion())) {
                 final String previousVersion = scHost.getVersion();
-                if (StringUtils.isNotBlank(structuredOutput.getVersion()) && !StringUtils.equals(previousVersion, structuredOutput.getVersion())) {
+                if (!StringUtils.equals(previousVersion, structuredOutput.getVersion())) {
                   scHost.setVersion(structuredOutput.getVersion());
                   if (previousVersion != null && !previousVersion.equals("UNKNOWN")) {
                     scHost.setUpgradeState(UpgradeState.COMPLETE);
                   }
                   scHostsRequireRecalculation.add(scHost);
                 }
-              } catch (JsonSyntaxException ex) {
-                //Json structure for component version was incorrect
-                //do nothing, pass this data further for processing
               }
             }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 6dabcbb..512ffdb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -75,7 +75,6 @@ import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
 import org.apache.ambari.server.controller.internal.RequestOperationLevel;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
@@ -98,7 +97,6 @@ import org.apache.ambari.server.security.ldap.LdapSyncDto;
 import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.CommandScriptDefinition;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.Config;
@@ -125,7 +123,6 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
-import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
@@ -207,8 +204,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   private AmbariLdapDataPopulator ldapDataPopulator;
   @Inject
   private RepositoryVersionDAO repositoryVersionDAO;
-  @Inject
-  private RepositoryVersionHelper repositoryVersionHelper;
 
   private MaintenanceStateHelper maintenanceStateHelper;
 
@@ -366,20 +361,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       StackId newStackId = new StackId(request.getStackVersion());
       c.setDesiredStackVersion(newStackId);
       clusters.setCurrentStackVersion(request.getClusterName(), newStackId);
-
-      try {
-        // Because Ambari may eventually support multiple clusters, it may be possible that a previously installed cluster
-        // already inserted the Repository Version for this stack and version.
-        RepositoryVersionEntity existingRepositoryVersion = repositoryVersionDAO.findByStackAndVersion(newStackId.getStackId(), newStackId.getStackVersion());
-        if (existingRepositoryVersion == null) {
-          repositoryVersionDAO.create(newStackId.getStackId(), newStackId.getStackVersion(), newStackId.getStackId(),
-              repositoryVersionHelper.getUpgradePackageNameSafe(newStackId.getStackId(), newStackId.getStackVersion(), newStackId.getStackVersion()),
-              repositoryVersionHelper.serializeOperatingSystems(stackInfo.getRepositories()));
-        }
-        c.createClusterVersion(stackId.getStackId(), stackId.getStackVersion(), getAuthName(), RepositoryVersionState.CURRENT);
-      } catch (Exception e) {
-        throw new AmbariException("Unable to create Repository Version and/or Cluster Version for Stack " + stackId.toString() + ". Error: " + e.getMessage());
-      }
     }
 
     if (request.getHostNames() != null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index da034ce..d9c9aec 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -469,7 +469,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     }
 
     UpgradeEntity entity = new UpgradeEntity();
-    // !!! FIXME not quite right here, upcoming patch is supposed to get this right
     entity.setFromVersion(cluster.getCurrentClusterVersion().getRepositoryVersion().getVersion());
     entity.setToVersion(version);
     entity.setUpgradeGroups(groupEntities);

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
index ed9fa24..d816102 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java
@@ -26,7 +26,10 @@ import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
 import org.apache.ambari.server.state.RepositoryVersionState;
+
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
 import javax.persistence.TypedQuery;
 
 import java.util.List;
@@ -125,6 +128,31 @@ public class HostVersionDAO {
   }
 
   /**
+   * Retrieve the single host version whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, of which there should be exactly one at all times
+   * for the given host.
+   *
+   * @param clusterName Cluster name
+   * @param hostName Host name
+   * @return Returns the single host version for this host whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, or {@code null} otherwise.
+   */
+  @RequiresSession
+  public HostVersionEntity findByHostAndStateCurrent(String clusterName, String hostName) {
+    try {
+      List<?> results = findByClusterHostAndState(clusterName, hostName, RepositoryVersionState.CURRENT);
+      if (results.isEmpty()) {
+        return null;
+      } else {
+        if (results.size() == 1) {
+          return (HostVersionEntity) results.get(0);
+        }
+      }
+      throw new NonUniqueResultException();
+    } catch (NoResultException ignored) {
+      return null;
+    }
+  }
+
+  /**
    * Retrieve the single host version for the given cluster, stack name, stack version, and host name.
    *
    * @param clusterName Cluster name

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/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 fd0188c..b344a05 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
@@ -173,7 +173,7 @@ public interface Cluster {
 
   /**
    * Create a cluster version for the given stack and version, whose initial state must either
-   * be either {@link RepositoryVersionState#CURRENT} (if no other cluster version exists) or
+   * be either {@link RepositoryVersionState#UPGRADING} (if no other cluster version exists) or
    * {@link RepositoryVersionState#INSTALLING} (if at exactly one CURRENT cluster version already exists).
    * @param stack Stack name
    * @param version Stack version

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/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 19a5f9f..bf5bf50 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
@@ -44,6 +44,7 @@ import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariSessionManager;
 import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.controller.ConfigurationResponse;
@@ -79,6 +80,7 @@ import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RequestScheduleEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ClusterHealthReport;
@@ -226,6 +228,9 @@ public class ClusterImpl implements Cluster {
   private RepositoryVersionDAO repositoryVersionDAO;
 
   @Inject
+  private Configuration configuration;
+
+  @Inject
   private AmbariSessionManager sessionManager;
 
   private volatile boolean svcHostsLoaded = false;
@@ -1258,13 +1263,18 @@ public class ClusterImpl implements Cluster {
       readWriteLock.writeLock().lock();
       try {
         Map<String, Host> hosts = clusters.getHostsForCluster(this.getClusterName());
-        String stackId = this.getCurrentStackVersion().getStackId();
+        StackId stackId = getCurrentStackVersion();
+
         ClusterVersionEntity clusterVersion = clusterVersionDAO.findByClusterAndStackAndVersion(this.getClusterName(),
-            stackId, repositoryVersion);
+            stackId.getStackId(), repositoryVersion);
 
         if (clusterVersion == null) {
-          throw new AmbariException(String.format("Repository version %s not found for cluster %s",
-                  repositoryVersion, getClusterName()));
+          if (clusterVersionDAO.findByCluster(getClusterName()).isEmpty()) {
+            createClusterVersionInternal(stackId.getStackId(), repositoryVersion, AuthorizationHelper.getAuthenticatedName(configuration.getAnonymousAuditName()), RepositoryVersionState.UPGRADING);
+            clusterVersion = clusterVersionDAO.findByClusterAndStackAndVersion(this.getClusterName(), stackId.getStackId(), repositoryVersion);
+          } else {
+            throw new AmbariException(String.format("Repository version %s not found for cluster %s", repositoryVersion, getClusterName()));
+          }
         }
 
         RepositoryVersionState worstState;
@@ -1277,7 +1287,7 @@ public class ClusterImpl implements Cluster {
           // anything else is not supported as of now
           return;
         }
-        worstState = RepositoryVersionState.UPGRADED;
+        worstState = RepositoryVersionState.CURRENT;
         for (Host host : hosts.values()) {
           String hostName = host.getHostName();
           if (host.getState() != HostState.HEALTHY) {
@@ -1286,19 +1296,20 @@ public class ClusterImpl implements Cluster {
                     hostName, worstState));
           }
 
-          HostVersionEntity hostVersion = hostVersionDAO.findByClusterStackVersionAndHost(this.getClusterName(),
-                  stackId, repositoryVersion, hostName);
-          if (hostVersion == null) {
-            LOG.warn(String.format("Repo version %s is not installed on host %s",
-                    repositoryVersion, hostName));
-            worstState = getWorstState(worstState, RepositoryVersionState.OUT_OF_SYNC);
-          } else {
-            worstState = getWorstState(worstState, hostVersion.getState());
+          HostVersionEntity hostVersion = hostVersionDAO.findByClusterStackVersionAndHost(this.getClusterName(), stackId.getStackId(), repositoryVersion, hostName);
+          if (clusterVersionDAO.findByClusterAndStateCurrent(getClusterName()) != null) { //TODO workaround to skip this check during clean install
+            if (hostVersion == null) {
+              LOG.warn(String.format("Repo version %s is not installed on host %s",
+                      repositoryVersion, hostName));
+              worstState = getWorstState(worstState, RepositoryVersionState.OUT_OF_SYNC);
+            } else {
+              worstState = getWorstState(worstState, hostVersion.getState());
+            }
           }
         }
         if (worstState != clusterVersion.getState()) {
           // Any mismatch will be catched while transitioning
-          transitionClusterVersion(stackId, repositoryVersion, worstState);
+          transitionClusterVersion(stackId.getStackId(), repositoryVersion, worstState);
         }
         clusterVersionDAO.merge(clusterVersion);
 
@@ -1332,47 +1343,13 @@ public class ClusterImpl implements Cluster {
     }
   }
 
-  /**
-   * Create a cluster version for the given stack and version, whose initial state must either
-   * be either {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT} (if no other cluster version exists) or
-   * {@link org.apache.ambari.server.state.RepositoryVersionState#INSTALLING} (if at exactly one CURRENT cluster version already exists).
-   * @param stack Stack name
-   * @param version Stack version
-   * @param userName User performing the operation
-   * @param state Initial state
-   * @throws AmbariException
-   */
   @Override
   public void createClusterVersion(String stack, String version, String userName, RepositoryVersionState state) throws AmbariException {
     clusterGlobalLock.readLock().lock();
     try {
       readWriteLock.writeLock().lock();
       try {
-        Set<RepositoryVersionState> allowedStates = new HashSet<RepositoryVersionState>();
-        Collection<ClusterVersionEntity> allClusterVersions = getAllClusterVersions();
-        if (allClusterVersions == null || allClusterVersions.isEmpty()) {
-          allowedStates.add(RepositoryVersionState.CURRENT);
-        } else {
-          allowedStates.add(RepositoryVersionState.INSTALLING);
-        }
-
-        if (! allowedStates.contains(state)) {
-          throw new AmbariException("The allowed state for a new cluster version must be within " + allowedStates);
-        }
-
-        ClusterVersionEntity existing = clusterVersionDAO.findByClusterAndStackAndVersion(this.getClusterName(), stack, version);
-        if (existing != null) {
-          throw new DuplicateResourceException("Duplicate item, a cluster version with stack=" + stack + ", version=" +
-              version + " for cluster " + this.getClusterName() + " already exists");
-        }
-
-        RepositoryVersionEntity repositoryVersionEntity = repositoryVersionDAO.findByStackAndVersion(stack, version);
-        if (repositoryVersionEntity == null) {
-          throw new AmbariException("Could not find repository version for stack=" + stack + ", version=" + version );
-        }
-
-        ClusterVersionEntity clusterVersionEntity = new ClusterVersionEntity(this.clusterEntity, repositoryVersionEntity, state, System.currentTimeMillis(), System.currentTimeMillis(), userName);
-        clusterVersionDAO.create(clusterVersionEntity);
+        createClusterVersionInternal(stack, version, userName, state);
       } finally {
         readWriteLock.writeLock().unlock();
       }
@@ -1382,6 +1359,40 @@ public class ClusterImpl implements Cluster {
   }
 
   /**
+   * See {@link #createClusterVersion}
+   *
+   * This method is intended to be called only when cluster lock is already acquired.
+   */
+  private void createClusterVersionInternal(String stack, String version, String userName, RepositoryVersionState state) throws AmbariException {
+    Set<RepositoryVersionState> allowedStates = new HashSet<RepositoryVersionState>();
+    Collection<ClusterVersionEntity> allClusterVersions = getAllClusterVersions();
+    if (allClusterVersions == null || allClusterVersions.isEmpty()) {
+      allowedStates.add(RepositoryVersionState.CURRENT);
+      allowedStates.add(RepositoryVersionState.UPGRADING);
+    } else {
+      allowedStates.add(RepositoryVersionState.INSTALLING);
+    }
+
+    if (! allowedStates.contains(state)) {
+      throw new AmbariException("The allowed state for a new cluster version must be within " + allowedStates);
+    }
+
+    ClusterVersionEntity existing = clusterVersionDAO.findByClusterAndStackAndVersion(this.getClusterName(), stack, version);
+    if (existing != null) {
+      throw new DuplicateResourceException("Duplicate item, a cluster version with stack=" + stack + ", version=" +
+          version + " for cluster " + this.getClusterName() + " already exists");
+    }
+
+    RepositoryVersionEntity repositoryVersionEntity = repositoryVersionDAO.findByStackAndVersion(stack, version);
+    if (repositoryVersionEntity == null) {
+      throw new AmbariException("Could not find repository version for stack=" + stack + ", version=" + version );
+    }
+
+    ClusterVersionEntity clusterVersionEntity = new ClusterVersionEntity(this.clusterEntity, repositoryVersionEntity, state, System.currentTimeMillis(), System.currentTimeMillis(), userName);
+    clusterVersionDAO.create(clusterVersionEntity);
+  }
+
+  /**
    * Transition an existing cluster version from one state to another.
    * @param stack Stack name
    * @param version Stack version
@@ -1428,6 +1439,9 @@ public class ClusterImpl implements Cluster {
             case UPGRADING:
               allowedStates.add(RepositoryVersionState.UPGRADED);
               allowedStates.add(RepositoryVersionState.UPGRADE_FAILED);
+              if (clusterVersionDAO.findByClusterAndStateCurrent(getClusterName()) == null) {
+                allowedStates.add(RepositoryVersionState.CURRENT);
+              }
               break;
             case UPGRADED:
               allowedStates.add(RepositoryVersionState.CURRENT);
@@ -1441,15 +1455,13 @@ public class ClusterImpl implements Cluster {
             throw new AmbariException("Invalid cluster version transition from " + existingClusterVersion.getState() + " to " + state);
           }
 
-          // There must be exactly one cluster version whose state is CURRENT at all times.
+          // There must be at most one cluster version whose state is CURRENT at all times.
           if (state == RepositoryVersionState.CURRENT) {
             ClusterVersionEntity currentVersion = clusterVersionDAO.findByClusterAndStateCurrent(this.getClusterName());
-            if (currentVersion == null) {
-              throw new AmbariException("Unable to find CURRENT cluster version for cluster " + this.getClusterName());
+            if (currentVersion != null) {
+              currentVersion.setState(RepositoryVersionState.INSTALLED);
+              clusterVersionDAO.merge(currentVersion);
             }
-
-            currentVersion.setState(RepositoryVersionState.INSTALLED);
-            clusterVersionDAO.merge(currentVersion);
           }
 
           existingClusterVersion.setState(state);

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index 9ec8c36..01148a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -516,7 +516,6 @@ public class ClustersImpl implements Clusters {
       }
 
       mapHostClusterEntities(hostname, cluster.getClusterId());
-      cluster.mapHostVersions(Sets.newHashSet(hostname), currentClusterVersion, RepositoryVersionState.CURRENT);
 
       host.refresh();
       cluster.refresh();

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/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 31606ca..3593eb3 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
@@ -33,6 +33,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.AlertDefinitionCommand;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.events.AlertHashInvalidationEvent;
 import org.apache.ambari.server.events.MaintenanceModeEvent;
@@ -70,6 +71,7 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceComponentHostEvent;
 import org.apache.ambari.server.state.ServiceComponentHostEventType;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.UpgradeState;
 import org.apache.ambari.server.state.alert.AlertDefinitionHash;
@@ -78,7 +80,9 @@ import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.SingleArcTransition;
 import org.apache.ambari.server.state.fsm.StateMachine;
 import org.apache.ambari.server.state.fsm.StateMachineFactory;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -123,6 +127,10 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   Clusters clusters;
   @Inject
   ConfigHelper helper;
+  @Inject
+  AmbariMetaInfo ambariMetaInfo;
+  @Inject
+  RepositoryVersionHelper repositoryVersionHelper;
 
   /**
    * Used for creating commands to send to the agents when alert definitions are
@@ -1708,6 +1716,10 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   @Override
   public void recalculateHostVersionState() throws AmbariException {
     final String version = getVersion();
+    if (version.equals("UNKNOWN")) {
+      // recalculate only if some particular version is set
+      return;
+    }
     final String hostName = getHostName();
     final HostEntity host = hostDAO.findByName(hostName);
     final Set<Cluster> clustersForHost = clusters.getClustersForHost(hostName);
@@ -1716,27 +1728,37 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
     }
     final Cluster cluster = clustersForHost.iterator().next();
     final StackId stack = cluster.getDesiredStackVersion();
-    final RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stack.getStackId(), version);
+    final StackInfo stackInfo = ambariMetaInfo.getStack(stack.getStackName(), stack.getStackVersion());
+    RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stack.getStackId(), version);
     if (repositoryVersion == null) {
-      LOG.debug("Repository version for stack " + stack.getStackId() + " for version " + version + " was not found");
-      return;
+      LOG.info("Creating new repository version " + stack.getStackName() + "-" + version);
+      repositoryVersion = repositoryVersionDAO.create(stack.getStackId(), version, stack.getStackName() + "-" + version,
+          repositoryVersionHelper.getUpgradePackageNameSafe(stack.getStackName(), stack.getStackVersion(), version),
+          repositoryVersionHelper.serializeOperatingSystems(stackInfo.getRepositories()));
     }
-    final HostVersionEntity hostVersionEntity = hostVersionDAO.findByClusterStackVersionAndHost(cluster.getClusterName(), repositoryVersion.getStack(), repositoryVersion.getVersion(), hostName);
+    HostVersionEntity hostVersionEntity = hostVersionDAO.findByClusterStackVersionAndHost(cluster.getClusterName(), repositoryVersion.getStack(), repositoryVersion.getVersion(), hostName);
     if (hostVersionEntity == null) {
-      LOG.debug(String.format("Host version version for host %s on cluster %s with stack %s and repository version %s was not found",
-          hostName, cluster.getClusterName(), repositoryVersion.getStack(), repositoryVersion.getVersion()));
-      return;
+      // there is no host version but we have a component on the host of that version. It implies that we have some repo version installed on that host
+      // and we can treat the host as being upgrading to that version
+      hostVersionEntity = new HostVersionEntity(hostName, repositoryVersion, RepositoryVersionState.UPGRADING);
+      hostVersionEntity.setHostEntity(host);
+      hostVersionDAO.create(hostVersionEntity);
     }
 
     final Collection<HostComponentStateEntity> allHostComponents = host.getHostComponentStateEntities();
     final Collection<HostComponentStateEntity> upgradedHostComponents = new HashSet<HostComponentStateEntity>();
+    final Collection<HostComponentStateEntity> versionedHostComponents = new HashSet<HostComponentStateEntity>();
     for (HostComponentStateEntity hostComponentStateEntity: allHostComponents) {
-      if (hostComponentStateEntity.getUpgradeState().equals(UpgradeState.COMPLETE) && !hostComponentStateEntity.getVersion().equals("UNKNOWN")) {
-        upgradedHostComponents.add(hostComponentStateEntity);
+      if (!hostComponentStateEntity.getVersion().equals("UNKNOWN")) {
+        versionedHostComponents.add(hostComponentStateEntity);
+        if (hostComponentStateEntity.getUpgradeState().equals(UpgradeState.COMPLETE) ) {
+          upgradedHostComponents.add(hostComponentStateEntity);
+        }
       }
     }
 
     // ZKFC is special because it is does not receive a RESTART action during a Rolling Upgrade.
+    @SuppressWarnings("unchecked")
     final Collection<HostComponentStateEntity> nonUpgradedHostComponents = CollectionUtils.subtract(allHostComponents, upgradedHostComponents);
     for (HostComponentStateEntity hostComponentStateEntity: nonUpgradedHostComponents) {
       if (hostComponentStateEntity.getComponentName().equalsIgnoreCase("ZKFC")) {
@@ -1744,17 +1766,41 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       }
     }
 
-    if (allHostComponents.size() == upgradedHostComponents.size() &&
+    if (allHostComponents.size() == upgradedHostComponents.size() && // all components are upgraded
+        haveSameVersion(upgradedHostComponents) && //have the same version
         (hostVersionEntity.getState().equals(RepositoryVersionState.INSTALLED) || hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADING))) {
       hostVersionEntity.setState(RepositoryVersionState.UPGRADED);
       hostVersionDAO.merge(hostVersionEntity);
-    }
-
-    if (!upgradedHostComponents.isEmpty() && upgradedHostComponents.size() < allHostComponents.size()) {
+    } else if (allHostComponents.size() == versionedHostComponents.size() && haveSameVersion(versionedHostComponents) && //all components have same version
+        hostVersionDAO.findByHostAndStateCurrent(cluster.getClusterName(), hostName) == null) { //and no CURRENT version exists
+      hostVersionEntity.setState(RepositoryVersionState.CURRENT);
+      hostVersionDAO.merge(hostVersionEntity);
+    } else if (!upgradedHostComponents.isEmpty() && upgradedHostComponents.size() < allHostComponents.size()) {
       hostVersionEntity.setState(RepositoryVersionState.UPGRADING);
       hostVersionDAO.merge(hostVersionEntity);
     }
 
     cluster.recalculateClusterVersionState(version);
   }
+
+  /**
+   * Checks that every component has the same version.
+   *
+   * @param hostComponents host components
+   * @return true if components have the same version
+   */
+  private boolean haveSameVersion(Collection<HostComponentStateEntity> hostComponents) {
+    if (hostComponents.isEmpty()) {
+      // should never happen
+      // but just in case: no components passed -> do not change host version
+      return false;
+    }
+    final String version = hostComponents.iterator().next().getVersion();
+    for (HostComponentStateEntity hostComponent : hostComponents) {
+      if (!StringUtils.equals(version, hostComponent.getVersion())) {
+        return false;
+      }
+    }
+    return true;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fe3f405f/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 57c0223..04b4f81 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
@@ -981,12 +981,12 @@ public class ClusterTest {
     assertNotNull(entityHDP2);
 
     List<HostVersionEntity> hostVersionsH1Before = hostVersionDAO.findByClusterAndHost("c1", "h1");
-    assertEquals(1, hostVersionsH1Before.size());
+    assertEquals(0, hostVersionsH1Before.size());
 
     c1.inferHostVersions(entityHDP2);
 
     List<HostVersionEntity> hostVersionsH1After = hostVersionDAO.findByClusterAndHost("c1", "h1");
-    assertEquals(2, hostVersionsH1After.size());
+    assertEquals(1, hostVersionsH1After.size());
 
     boolean checked = false;
     for (HostVersionEntity entity : hostVersionsH1After) {
@@ -1003,7 +1003,7 @@ public class ClusterTest {
     c1.inferHostVersions(entityHDP2);
 
     hostVersionsH1After = hostVersionDAO.findByClusterAndHost("c1", "h1");
-    assertEquals(2, hostVersionsH1After.size());
+    assertEquals(1, hostVersionsH1After.size());
 
     checked = false;
     for (HostVersionEntity entity : hostVersionsH1After) {