You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/03/02 20:07:04 UTC

[1/2] ambari git commit: AMBARI-9805. RU - Bug fixes for Host Version transition and Finalize (alejandro)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.0.0 01e6dd3b9 -> f5c7ac418


http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/role_command_order.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/role_command_order.json b/ambari-server/src/test/resources/stacks/HDP/2.2.0/role_command_order.json
new file mode 100644
index 0000000..656bb63
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/role_command_order.json
@@ -0,0 +1,81 @@
+{
+  "_comment" : "Record format:",
+  "_comment" : "blockedRole-blockedCommand: [blockerRole1-blockerCommand1, blockerRole2-blockerCommand2, ...]",
+  "general_deps" : {
+    "_comment" : "dependencies for all cases",
+    "HBASE_MASTER-START": ["ZOOKEEPER_SERVER-START, ZOOKEEPER_SERVER-START"],
+    "OOZIE_SERVER-START": ["JOBTRACKER-START", "TASKTRACKER-START"],
+    "WEBHCAT_SERVER-START": ["TASKTRACKER-START", "HIVE_SERVER-START"],
+    "HIVE_METASTORE-START": ["MYSQL_SERVER-START"],
+    "HIVE_SERVER-START": ["TASKTRACKER-START", "MYSQL_SERVER-START"],
+    "HUE_SERVER-START": ["HIVE_SERVER-START", "HCAT-START", "OOZIE_SERVER-START"],
+    "FLUME_HANDLER-START": ["OOZIE_SERVER-START"],
+    "MAPREDUCE_SERVICE_CHECK-SERVICE_CHECK": ["JOBTRACKER-START", "TASKTRACKER-START"],
+    "OOZIE_SERVICE_CHECK-SERVICE_CHECK": ["OOZIE_SERVER-START"],
+    "WEBHCAT_SERVICE_CHECK-SERVICE_CHECK": ["WEBHCAT_SERVER-START"],
+    "HBASE_SERVICE_CHECK-SERVICE_CHECK": ["HBASE_MASTER-START", "HBASE_REGIONSERVER-START"],
+    "HIVE_SERVICE_CHECK-SERVICE_CHECK": ["HIVE_SERVER-START", "HIVE_METASTORE-START"],
+    "HCAT_SERVICE_CHECK-SERVICE_CHECK": ["HIVE_SERVER-START"],
+    "PIG_SERVICE_CHECK-SERVICE_CHECK": ["JOBTRACKER-START", "TASKTRACKER-START"],
+    "SQOOP_SERVICE_CHECK-SERVICE_CHECK": ["JOBTRACKER-START", "TASKTRACKER-START"],
+    "ZOOKEEPER_SERVICE_CHECK-SERVICE_CHECK": ["ZOOKEEPER_SERVER-START"],
+    "ZOOKEEPER_QUORUM_SERVICE_CHECK-SERVICE_CHECK": ["ZOOKEEPER_SERVER-START"],
+    "ZOOKEEPER_SERVER-STOP" : ["HBASE_MASTER-STOP", "HBASE_REGIONSERVER-STOP"],
+    "HBASE_MASTER-STOP": ["HBASE_REGIONSERVER-STOP"],
+    "TASKTRACKER-UPGRADE": ["JOBTRACKER-UPGRADE"],
+    "MAPREDUCE_CLIENT-UPGRADE": ["TASKTRACKER-UPGRADE", "JOBTRACKER-UPGRADE"],
+    "ZOOKEEPER_SERVER-UPGRADE": ["MAPREDUCE_CLIENT-UPGRADE"],
+    "ZOOKEEPER_CLIENT-UPGRADE": ["ZOOKEEPER_SERVER-UPGRADE"],
+    "HBASE_MASTER-UPGRADE": ["ZOOKEEPER_CLIENT-UPGRADE"],
+    "HBASE_REGIONSERVER-UPGRADE": ["HBASE_MASTER-UPGRADE"],
+    "HBASE_CLIENT-UPGRADE": ["HBASE_REGIONSERVER-UPGRADE"],
+    "HIVE_SERVER-UPGRADE" : ["HBASE_CLIENT-UPGRADE"],
+    "HIVE_METASTORE-UPGRADE" : ["HIVE_SERVER-UPGRADE"],
+    "MYSQL_SERVER-UPGRADE": ["HIVE_METASTORE-UPGRADE"],
+    "HIVE_CLIENT-UPGRADE": ["MYSQL_SERVER-UPGRADE"],
+    "HCAT-UPGRADE": ["HIVE_CLIENT-UPGRADE"],
+    "OOZIE_SERVER-UPGRADE" : ["HCAT-UPGRADE"],
+    "OOZIE_CLIENT-UPGRADE" : ["OOZIE_SERVER-UPGRADE"],
+    "WEBHCAT_SERVER-UPGRADE" : ["OOZIE_CLIENT-UPGRADE"],
+    "PIG-UPGRADE" : ["WEBHCAT_SERVER-UPGRADE"],
+    "SQOOP-UPGRADE" : ["PIG-UPGRADE"],
+    "GANGLIA_SERVER-UPGRADE" : ["SQOOP-UPGRADE"],
+    "GANGLIA_MONITOR-UPGRADE" : ["GANGLIA_SERVER-UPGRADE"]
+  },
+  "_comment" : "GLUSTERFS-specific dependencies",
+  "optional_glusterfs": {
+    "HBASE_MASTER-START": ["PEERSTATUS-START"],
+    "JOBTRACKER-START": ["PEERSTATUS-START"],
+    "TASKTRACKER-START": ["PEERSTATUS-START"],
+    "GLUSTERFS_SERVICE_CHECK-SERVICE_CHECK": ["PEERSTATUS-START"],
+    "JOBTRACKER-UPGRADE": ["GLUSTERFS_CLIENT-UPGRADE"]
+  },
+  "_comment" : "Dependencies that are used when GLUSTERFS is not present in cluster",
+  "optional_no_glusterfs": {
+    "SECONDARY_NAMENODE-START": ["NAMENODE-START"],
+    "RESOURCEMANAGER-START": ["NAMENODE-START", "DATANODE-START"],
+    "NODEMANAGER-START": ["NAMENODE-START", "DATANODE-START", "RESOURCEMANAGER-START"],
+    "HISTORYSERVER-START": ["NAMENODE-START", "DATANODE-START"],
+    "HBASE_MASTER-START": ["NAMENODE-START", "DATANODE-START"],
+    "JOBTRACKER-START": ["NAMENODE-START", "DATANODE-START"],
+    "TASKTRACKER-START": ["NAMENODE-START", "DATANODE-START"],
+    "HIVE_SERVER-START": ["DATANODE-START"],
+    "WEBHCAT_SERVER-START": ["DATANODE-START"],
+    "HDFS_SERVICE_CHECK-SERVICE_CHECK": ["NAMENODE-START", "DATANODE-START",
+        "SECONDARY_NAMENODE-START"],
+    "MAPREDUCE2_SERVICE_CHECK-SERVICE_CHECK": ["NODEMANAGER-START",
+        "RESOURCEMANAGER-START", "HISTORYSERVER-START", "YARN_SERVICE_CHECK-SERVICE_CHECK"],
+    "YARN_SERVICE_CHECK-SERVICE_CHECK": ["NODEMANAGER-START", "RESOURCEMANAGER-START"],
+    "RESOURCEMANAGER_SERVICE_CHECK-SERVICE_CHECK": ["RESOURCEMANAGER-START"],
+    "PIG_SERVICE_CHECK-SERVICE_CHECK": ["RESOURCEMANAGER-START", "NODEMANAGER-START"],
+    "NAMENODE-STOP": ["JOBTRACKER-STOP", "TASKTRACKER-STOP", "RESOURCEMANAGER-STOP",
+        "NODEMANAGER-STOP", "HISTORYSERVER-STOP", "HBASE_MASTER-STOP"],
+    "DATANODE-STOP": ["JOBTRACKER-STOP", "TASKTRACKER-STOP", "RESOURCEMANAGER-STOP",
+        "NODEMANAGER-STOP", "HISTORYSERVER-STOP", "HBASE_MASTER-STOP"],
+    "SECONDARY_NAMENODE-UPGRADE": ["NAMENODE-UPGRADE"],
+    "DATANODE-UPGRADE": ["SECONDARY_NAMENODE-UPGRADE"],
+    "HDFS_CLIENT-UPGRADE": ["DATANODE-UPGRADE"],
+    "JOBTRACKER-UPGRADE": ["HDFS_CLIENT-UPGRADE"]
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/GANGLIA/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/GANGLIA/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/GANGLIA/metainfo.xml
new file mode 100644
index 0000000..1fe4aec
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/GANGLIA/metainfo.xml
@@ -0,0 +1,39 @@
+<?xml version="1.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.
+-->
+<metainfo>
+  <schemaVersion>2.0</schemaVersion>
+  <services>
+    <service>
+      <name>GANGLIA</name>
+      <comment>Ganglia Metrics Collection system (&lt;a href=&quot;http://oss.oetiker.ch/rrdtool/&quot; target=&quot;_blank&quot;&gt;RRDTool&lt;/a&gt; will be installed too)</comment>
+      <version>3.5.0</version>
+
+      <components>
+        <component>
+          <name>GANGLIA_SERVER</name>
+          <versionAdvertised>false</versionAdvertised>
+        </component>
+
+        <component>
+          <name>GANGLIA_MONITOR</name>
+          <versionAdvertised>false</versionAdvertised>
+        </component>
+      </components>
+    </service>
+  </services>
+</metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml
new file mode 100644
index 0000000..2bd1f99
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml
@@ -0,0 +1,59 @@
+<?xml version="1.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.
+-->
+<metainfo>
+  <schemaVersion>2.0</schemaVersion>
+  <services>
+    <service>
+      <name>HDFS</name>
+      <comment>Apache Hadoop Distributed File System</comment>
+      <version>2.1.0.2.0.6.0</version>
+
+      <components>
+        <component>
+          <name>NAMENODE</name>
+          <versionAdvertised>true</versionAdvertised>
+        </component>
+
+        <component>
+          <name>DATANODE</name>
+          <versionAdvertised>false</versionAdvertised>
+        </component>
+
+        <component>
+          <name>SECONDARY_NAMENODE</name>
+          <versionAdvertised>false</versionAdvertised>
+        </component>
+
+        <component>
+          <name>HDFS_CLIENT</name>
+          <versionAdvertised>true</versionAdvertised>
+        </component>
+
+        <component>
+          <name>JOURNALNODE</name>
+          <versionAdvertised>true</versionAdvertised>
+        </component>
+
+        <component>
+          <name>ZKFC</name>
+          <versionAdvertised>false</versionAdvertised>
+        </component>
+      </components>
+    </service>
+  </services>
+</metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml
new file mode 100644
index 0000000..ed0a132
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml
@@ -0,0 +1,40 @@
+<?xml version="1.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.
+-->
+<metainfo>
+  <schemaVersion>2.0</schemaVersion>
+  <services>
+    <service>
+      <name>ZOOKEEPER</name>
+      <displayName>ZooKeeper</displayName>
+      <comment>Centralized service which provides highly reliable distributed coordination</comment>
+      <version>3.4.5.2.0</version>
+
+      <components>
+        <component>
+          <name>ZOOKEEPER_SERVER</name>
+          <versionAdvertised>true</versionAdvertised>
+        </component>
+
+        <component>
+          <name>ZOOKEEPER_CLIENT</name>
+          <versionAdvertised>true</versionAdvertised>
+        </component>
+      </components>
+    </service>
+  </services>
+</metainfo>


[2/2] ambari git commit: AMBARI-9805. RU - Bug fixes for Host Version transition and Finalize (alejandro)

Posted by al...@apache.org.
AMBARI-9805. RU - Bug fixes for Host Version transition and Finalize (alejandro)


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

Branch: refs/heads/branch-2.0.0
Commit: f5c7ac418ee5566dbee7dc2f06365b80a46fa2c0
Parents: 01e6dd3
Author: Alejandro Fernandez <af...@hortonworks.com>
Authored: Mon Mar 2 11:06:13 2015 -0800
Committer: Alejandro Fernandez <af...@hortonworks.com>
Committed: Mon Mar 2 11:06:13 2015 -0800

----------------------------------------------------------------------
 .../upgrades/FinalizeUpgradeAction.java         |  13 +-
 .../org/apache/ambari/server/state/Cluster.java |  28 +-
 .../server/state/cluster/ClusterImpl.java       | 160 ++---
 .../svccomphost/ServiceComponentHostImpl.java   |  19 +-
 .../ServiceComponentHostSummary.java            |  62 +-
 .../AmbariManagementControllerTest.java         |   2 +-
 .../ambari/server/stack/StackManagerTest.java   |   4 +-
 .../server/state/cluster/ClusterTest.java       | 715 +++++++++++++++----
 .../HDP/2.0.5/services/GANGLIA/metainfo.xml     |   2 +
 .../stacks/HDP/2.0.5/services/HDFS/metainfo.xml |   6 +
 .../HDP/2.0.5/services/ZOOKEEPER/metainfo.xml   |   1 +
 .../resources/stacks/HDP/2.2.0/metainfo.xml     |  24 +
 .../resources/stacks/HDP/2.2.0/repos/hdp.json   |  10 +
 .../stacks/HDP/2.2.0/repos/repoinfo.xml         |  62 ++
 .../stacks/HDP/2.2.0/role_command_order.json    |  81 +++
 .../HDP/2.2.0/services/GANGLIA/metainfo.xml     |  39 +
 .../stacks/HDP/2.2.0/services/HDFS/metainfo.xml |  59 ++
 .../HDP/2.2.0/services/ZOOKEEPER/metainfo.xml   |  40 ++
 18 files changed, 1037 insertions(+), 290 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
index 4dcdc94..d8e5e92 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/FinalizeUpgradeAction.java
@@ -125,7 +125,7 @@ public class FinalizeUpgradeAction extends AbstractServerAction {
       List<HostVersionEntity> hostVersions = hostVersionDAO.findByClusterStackAndVersion(clusterName, stackId, version);
 
       // Will include hosts whose state is UPGRADED, and potentially INSTALLED
-      Set<HostVersionEntity> hostsWithAllowedVersion = new HashSet<HostVersionEntity>();
+      Set<HostVersionEntity> hostVersionsAllowed = new HashSet<HostVersionEntity>();
       Set<String> hostsWithoutCorrectVersionState = new HashSet<String>();
       Set<String> hostsToUpdate = new HashSet<String>();
       // If true, then the cluster version is still in UPGRADING and allowed to transition to UPGRADED, and then CURRENT
@@ -152,7 +152,7 @@ public class FinalizeUpgradeAction extends AbstractServerAction {
         }
 
         if (isStateCorrect) {
-          hostsWithAllowedVersion.add(hostVersion);
+          hostVersionsAllowed.add(hostVersion);
           hostsToUpdate.add(hostVersion.getHostName());
         } else {
           hostsWithoutCorrectVersionState.add(hostVersion.getHostName());
@@ -169,7 +169,7 @@ public class FinalizeUpgradeAction extends AbstractServerAction {
         throw new AmbariException(message);
       }
 
-      // Allow the cluster version to transition from UPGRADING to CURRENT
+      // May need to first transition to UPGRADED
       if (atLeastOneHostInInstalledState) {
         cluster.transitionClusterVersion(stackId, version, RepositoryVersionState.UPGRADED);
         upgradingClusterVersion = clusterVersionDAO.findByClusterAndStackAndVersion(clusterName,
@@ -181,9 +181,10 @@ public class FinalizeUpgradeAction extends AbstractServerAction {
             upgradingClusterVersion.getState(), RepositoryVersionState.CURRENT.toString()));
       }
 
-      outSB.append(String.format("Will finalize the upgraded state of host components in %d host(s).\n", hostsWithAllowedVersion.size()));
+      outSB.append(String.format("Will finalize the upgraded state of host components in %d host(s).\n", hostVersionsAllowed.size()));
 
-      for (HostVersionEntity hostVersion : hostsWithAllowedVersion) {
+      // Reset the upgrade state
+      for (HostVersionEntity hostVersion : hostVersionsAllowed) {
         Collection<HostComponentStateEntity> hostComponentStates = hostComponentStateDAO.findByHost(hostVersion.getHostName());
         for (HostComponentStateEntity hostComponentStateEntity: hostComponentStates) {
           hostComponentStateEntity.setUpgradeState(UpgradeState.NONE);
@@ -191,7 +192,7 @@ public class FinalizeUpgradeAction extends AbstractServerAction {
         }
       }
 
-      outSB.append(String.format("Will finalize the version for %d host(s).\n", hostsWithAllowedVersion.size()));
+      outSB.append(String.format("Will finalize the version for %d host(s).\n", hostVersionsAllowed.size()));
 
       // Impacts all hosts that have a version
       cluster.mapHostVersions(hostsToUpdate, upgradingClusterVersion, RepositoryVersionState.CURRENT);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/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 6b8a917..9b424b8 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
@@ -152,23 +152,10 @@ public interface Cluster {
    * @throws AmbariException
    */
   public void inferHostVersions(ClusterVersionEntity sourceClusterVersion) throws AmbariException;
-
-  /**
-   * Update state of a cluster stack version for cluster based on states of host versions.
-   * May be called multiple times.
-   * As of now, only transition from INSTALLING to INSTALLING/INSTALLED/INSTALL_FAILED/OUT_OF_SYNC
-   * is supported
-   *
-   * @param repositoryVersion repository version (e.g. 2.2.1.0-100)
-   *
-   * @throws AmbariException
-   */
-  void recalculateClusterVersionState(String repositoryVersion) throws AmbariException;
-
+  
   /**
    * For a given host, will either either update an existing Host Version Entity for the given version, or create
-   * one if it doesn't exist. The object will be created with a state of
-   * {@link org.apache.ambari.server.state.RepositoryVersionState#UPGRADING}
+   * one if it doesn't exist
    *
    * @param host Host Entity object
    * @param repositoryVersion Repository Version that the host is transitioning to
@@ -179,10 +166,14 @@ public interface Cluster {
   public HostVersionEntity transitionHostVersionState(HostEntity host, final RepositoryVersionEntity repositoryVersion, final StackId stack) throws AmbariException;
 
   /**
+   * Update state of a cluster stack version for cluster based on states of host versions.
+   * @param repositoryVersion repository version (e.g. 2.2.1.0-100)
+   * @throws AmbariException
+   */
+  void recalculateClusterVersionState(String repositoryVersion) throws AmbariException;
+
+  /**
    * Update state of all cluster stack versions for cluster based on states of host versions.
-   * May be called multiple times.
-   * As of now, only transition from INSTALLING to INSTALLING/INSTALLED/INSTALL_FAILED/OUT_OF_SYNC
-   * is supported
    * @throws AmbariException
    */
   public void recalculateAllClusterVersionStates() throws AmbariException;
@@ -199,7 +190,6 @@ public interface Cluster {
    */
   public void createClusterVersion(String stack, String version, String userName, RepositoryVersionState state) throws AmbariException;
 
-
   /**
    * Transition an existing cluster version from one state to another.
    * @param stack Stack name

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/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 13d986d..638e4da 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
@@ -30,6 +30,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -172,6 +173,10 @@ public class ClusterImpl implements Cluster {
 
   private final ReadWriteLock clusterGlobalLock = new ReentrantReadWriteLock();
 
+  // This is a lock for operations that do not need to be cluster global
+  private final ReentrantReadWriteLock hostTransitionStateLock = new ReentrantReadWriteLock();
+  private final Lock hostTransitionStateWriteLock = hostTransitionStateLock.writeLock();
+
   private ClusterEntity clusterEntity;
 
   private final ConfigVersionHelper configVersionHelper;
@@ -1176,6 +1181,11 @@ public class ClusterImpl implements Cluster {
     return RepositoryVersionState.OUT_OF_SYNC;
   }
 
+  /**
+   * Recalculate what the Cluster Version state should be, depending on the individual Host Versions.
+   * @param repositoryVersion Repository version (e.g., 2.2.0.0-1234)
+   * @throws AmbariException
+   */
   @Override
   public void recalculateClusterVersionState(String repositoryVersion) throws AmbariException {
     if (repositoryVersion == null) {
@@ -1196,6 +1206,9 @@ public class ClusterImpl implements Cluster {
         if (clusterVersionDAO.findByCluster(getClusterName()).isEmpty()) {
           // During an Ambari Upgrade from 1.7.0 -> 2.0.0, the Cluster Version
           // will not exist, so bootstrap it.
+          // This can still fail if the Repository Version has not yet been created,
+          // which can happen if the first HostComponentState to trigger this method
+          // cannot advertise a version.
           createClusterVersionInternal(
               stackId.getStackId(),
               repositoryVersion,
@@ -1203,10 +1216,18 @@ public class ClusterImpl implements Cluster {
               RepositoryVersionState.UPGRADING);
           clusterVersion = clusterVersionDAO.findByClusterAndStackAndVersion(
               getClusterName(), stackId.getStackId(), repositoryVersion);
+
+          if (clusterVersion == null) {
+            LOG.warn(String.format(
+                "Could not create a cluster version for cluster %s and stack %s using repo version %s",
+                getClusterName(), stackId.getStackId(), repositoryVersion));
+            return;
+          }
         } else {
-          throw new AmbariException(String.format(
+          LOG.warn(String.format(
               "Repository version %s not found for cluster %s",
               repositoryVersion, getClusterName()));
+          return;
         }
       }
 
@@ -1292,77 +1313,52 @@ public class ClusterImpl implements Cluster {
 
   /**
    * Transition the Host Version across states.
-   * If a Host Component has a valid version, then create a Host Version if it does not already exist.
-   * Pre-req is for a Repository Version to exist.
-   * If no no cluster version exists, or exactly one, then potentially transition to CURRENT when no more work is needed.
-   * If in the middle of an upgrade and no more work exists, transition to UPGRADED.
-   * Otherwise, if a mismatch of versions exist, transition to UPGRADING since in the middle of an upgrade.
-   * @param host
-   * @param repositoryVersion
-   * @param stack
+   * @param host Host object
+   * @param repositoryVersion Repository Version with stack and version information
+   * @param stack Stack information
    * @throws AmbariException
    */
-  @Override
   @Transactional
   public HostVersionEntity transitionHostVersionState(HostEntity host, final RepositoryVersionEntity repositoryVersion, final StackId stack) throws AmbariException {
-    List<HostVersionEntity> hostVersions = hostVersionDAO.findByHost(host.getHostName());
-
-    // Check if there is a CURRENT version for host
-    boolean currentHostVerExists = false;
-    if (hostVersions != null && ! hostVersions.isEmpty()) {
-      for (HostVersionEntity hostVersion : hostVersions) {
-        if (hostVersion.getState() == RepositoryVersionState.CURRENT) {
-          currentHostVerExists = true;
-        }
+    HostVersionEntity hostVersionEntity = hostVersionDAO.findByClusterStackVersionAndHost(getClusterName(), repositoryVersion.getStack(), repositoryVersion.getVersion(), host.getHostName());
+
+    hostTransitionStateWriteLock.lock();
+    try {
+      // Create one if it doesn't already exist. It will be possible to make further transitions below.
+      if (hostVersionEntity == null) {
+        hostVersionEntity = new HostVersionEntity(host.getHostName(), repositoryVersion, RepositoryVersionState.UPGRADING);
+        hostVersionEntity.setHostEntity(host);
+        hostVersionDAO.create(hostVersionEntity);
       }
-    }
 
-    HostVersionEntity hostVersionEntity = hostVersionDAO.findByClusterStackVersionAndHost(getClusterName(),
-            repositoryVersion.getStack(), repositoryVersion.getVersion(), host.getHostName());
-    if (hostVersionEntity == null) {
-      // Since the host has no version, allow bootstrapping a version
-      hostVersionEntity = new HostVersionEntity(host.getHostName(), repositoryVersion, RepositoryVersionState.UPGRADING);
-      hostVersionEntity.setHostEntity(host);
-      hostVersionDAO.create(hostVersionEntity);
-    }
+      HostVersionEntity currentVersionEntity = hostVersionDAO.findByHostAndStateCurrent(getClusterName(), host.getHostName());
+      boolean isCurrentPresent = (currentVersionEntity != null);
+      final ServiceComponentHostSummary hostSummary = new ServiceComponentHostSummary(ambariMetaInfo, host, stack);
 
-    final ServiceComponentHostSummary hostSummary = new ServiceComponentHostSummary(ambariMetaInfo, host, stack);
-    final Collection<HostComponentStateEntity> versionedHostComponents = hostSummary.getVersionedHostComponents();
+      if (!isCurrentPresent) {
+        // Transition from UPGRADING -> CURRENT. This is allowed because Host Version Entity is bootstrapped in an UPGRADING state.
+        if (hostSummary.isUpgradeFinished() && hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADING)) {
+          hostVersionEntity.setState(RepositoryVersionState.CURRENT);
+          hostVersionDAO.merge(hostVersionEntity);
+        }
+      } else {
+        // Handle transitions during a Rolling Upgrade
 
-    // If 0 or 1 cluster version exists, then a brand new cluster permits the host to transition from UPGRADING->CURRENT
-    // If multiple cluster versions exist, then it means that the change in versions is happening due to an Upgrade,
-    // so should only allow transitioning to UPGRADED or UPGRADING, depending on further circumstances.
-    List<ClusterVersionEntity> clusterVersions = clusterVersionDAO.findByCluster(getClusterName());
-    if (clusterVersions.size() <= 1 || ! currentHostVerExists) {
-      // Transition from UPGRADING -> CURRENT. This is allowed because Host Version Entity is bootstrapped in an UPGRADING state.
-      // This also covers hosts that do not advertise a version when the cluster was created, and then have another component added
-      // that does advertise a version.
-      if (hostSummary.haveAllComponentsFinishedAdvertisingVersion() &&
-          (hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADING) || hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADED)) &&
-          ServiceComponentHostSummary.haveSameVersion(versionedHostComponents)) {
-        hostVersionEntity.setState(RepositoryVersionState.CURRENT);
-        hostVersionDAO.merge(hostVersionEntity);
-      }
-    } else {
-      // Transition from UPGRADING -> UPGRADED.
-      // We should never transition directly from INSTALLED -> UPGRADED without first going to UPGRADING because
-      // they belong in different phases (1. distribute bits 2. perform upgrade).
-      if (hostSummary.haveAllComponentsFinishedAdvertisingVersion() &&
-          hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADING) &&
-          ServiceComponentHostSummary.haveSameVersion(versionedHostComponents)) {
-        hostVersionEntity.setState(RepositoryVersionState.UPGRADED);
-        hostVersionDAO.merge(hostVersionEntity);
-      } else{
-        // HostVersion is INSTALLED and an upgrade is in-progress because at least 2 components have different versions,
-        // Or the host has no components that advertise a version, so still consider it as UPGRADING.
-        if (hostVersionEntity.getState().equals(RepositoryVersionState.INSTALLED) && versionedHostComponents.size() > 0 &&
-          !ServiceComponentHostSummary.haveSameVersion(versionedHostComponents)) {
+        // If a host only has one Component to update, that single report can still transition the host version from
+        // INSTALLED->UPGRADING->UPGRADED in one shot.
+        if (hostSummary.isUpgradeInProgress(currentVersionEntity.getRepositoryVersion().getVersion()) && hostVersionEntity.getState().equals(RepositoryVersionState.INSTALLED)) {
           hostVersionEntity.setState(RepositoryVersionState.UPGRADING);
           hostVersionDAO.merge(hostVersionEntity);
         }
+
+        if (hostSummary.isUpgradeFinished() && hostVersionEntity.getState().equals(RepositoryVersionState.UPGRADING)) {
+          hostVersionEntity.setState(RepositoryVersionState.UPGRADED);
+          hostVersionDAO.merge(hostVersionEntity);
+        }
       }
+    } finally {
+      hostTransitionStateWriteLock.unlock();
     }
-
     return hostVersionEntity;
   }
 
@@ -1420,7 +1416,8 @@ public class ClusterImpl implements Cluster {
 
     RepositoryVersionEntity repositoryVersionEntity = repositoryVersionDAO.findByStackAndVersion(stack, version);
     if (repositoryVersionEntity == null) {
-      throw new AmbariException("Could not find repository version for stack=" + stack + ", version=" + version );
+      LOG.warn("Could not find repository version for stack=" + stack + ", version=" + version);
+      return;
     }
 
     ClusterVersionEntity clusterVersionEntity = new ClusterVersionEntity(clusterEntity, repositoryVersionEntity, state, System.currentTimeMillis(), System.currentTimeMillis(), userName);
@@ -1517,43 +1514,31 @@ public class ClusterImpl implements Cluster {
             Collection<HostVersionEntity> versions = hostVersionDAO.findByHost(
                 he.getHostName());
 
-            if (null == versions || versions.isEmpty()) {
-              // no versions whatsoever
-              HostVersionEntity hve = new HostVersionEntity();
-              hve.setHostEntity(he);
-              hve.setHostName(he.getHostName());
-              hve.setRepositoryVersion(existingClusterVersion.getRepositoryVersion());
-              hve.setState(state);
-              hostVersionDAO.create(hve);
-            } else {
-              HostVersionEntity target = null;
-              // set anything that is marked current as installed
+            HostVersionEntity target = null;
+            if (null != versions) {
+              // Set anything that was previously marked CURRENT as INSTALLED, and the matching version as CURRENT
               for (HostVersionEntity entity : versions) {
-                if (entity.getRepositoryVersion().getId().equals(
-                    existingClusterVersion.getRepositoryVersion().getId())) {
+                if (entity.getRepositoryVersion().getId().equals(existingClusterVersion.getRepositoryVersion().getId())) {
                   target = entity;
                   target.setState(state);
                   hostVersionDAO.merge(target);
-                } else if (entity.getState() == state) {
+                } else if (entity.getState() == RepositoryVersionState.CURRENT) {
                   entity.setState(RepositoryVersionState.INSTALLED);
                   hostVersionDAO.merge(entity);
                 }
               }
-              if (null == target) {
-                // not found in existing list, make one
-                HostVersionEntity hve = new HostVersionEntity();
-                hve.setHostEntity(he);
-                hve.setHostName(he.getHostName());
-                hve.setRepositoryVersion(existingClusterVersion.getRepositoryVersion());
-                hve.setState(state);
-                hostVersionDAO.create(hve);
-              }
-
+            }
+            if (null == target) {
+              // If no matching version was found, create one with the desired state
+              HostVersionEntity hve = new HostVersionEntity();
+              hve.setHostEntity(he);
+              hve.setHostName(he.getHostName());
+              hve.setRepositoryVersion(existingClusterVersion.getRepositoryVersion());
+              hve.setState(state);
+              hostVersionDAO.create(hve);
             }
           }
         }
-
-
       }
     } catch (RollbackException e) {
       String message = "Unable to transition stack " + stack + " at version "
@@ -1586,12 +1571,9 @@ public class ClusterImpl implements Cluster {
         return true;
       }
     }
-
-
     return false;
   }
 
-
   @Override
   public void setCurrentStackVersion(StackId stackVersion)
     throws AmbariException {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/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 6d7455e..fe5397b 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
@@ -1501,15 +1501,18 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
     final StackId stackId = cluster.getDesiredStackVersion();
     final StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
 
-    RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stackId.getStackId(), version);
-    if (repositoryVersion == null) {
-      repositoryVersion = createRepositoryVersion(version, stackId, stackInfo);
-    }
+    writeLock.lock();
+    try {
+      RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stackId.getStackId(), version);
+      if (repositoryVersion == null) {
+        repositoryVersion = createRepositoryVersion(version, stackId, stackInfo);
+      }
 
-    final HostEntity host = hostDAO.findByName(hostName);
-    cluster.transitionHostVersionState(host, repositoryVersion, stackId);
+      final HostEntity host = hostDAO.findByName(hostName);
+      cluster.transitionHostVersionState(host, repositoryVersion, stackId);
+    } finally {
+      writeLock.unlock();
+    }
     return version;
   }
-
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/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
index ef14f0b..1c36143 100644
--- 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
@@ -19,7 +19,6 @@
 package org.apache.ambari.server.state.svccomphost;
 
 
-import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
@@ -31,6 +30,7 @@ import org.apache.commons.lang.StringUtils;
 
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Set;
 
 
 /**
@@ -39,26 +39,33 @@ import java.util.HashSet;
 public class ServiceComponentHostSummary  {
 
   private Collection<HostComponentStateEntity> allHostComponents;
-  private Collection<HostComponentStateEntity> versionedHostComponents;
-  private Collection<HostComponentStateEntity> noVersionNeededComponents;
+  private Collection<HostComponentStateEntity> haveAdvertisedVersion;
+  private Collection<HostComponentStateEntity> waitingToAdvertiseVersion;
+  private Collection<HostComponentStateEntity> noVersionToAdvertise;
+  private Set<String> versions;
 
 
   public ServiceComponentHostSummary(AmbariMetaInfo ambariMetaInfo, HostEntity host, String stackName, String stackVersion) throws AmbariException {
     allHostComponents = host.getHostComponentStateEntities();
-    versionedHostComponents = new HashSet<HostComponentStateEntity>();
-    noVersionNeededComponents = new HashSet<HostComponentStateEntity>();
+    haveAdvertisedVersion = new HashSet<HostComponentStateEntity>();
+    waitingToAdvertiseVersion = new HashSet<HostComponentStateEntity>();
+    noVersionToAdvertise = new HashSet<HostComponentStateEntity>();
+    versions = new HashSet<String>();
 
     for (HostComponentStateEntity hostComponentStateEntity: allHostComponents) {
-      if (!hostComponentStateEntity.getVersion().equalsIgnoreCase(State.UNKNOWN.toString())) {
-        versionedHostComponents.add(hostComponentStateEntity);
-      } else {
-        // Some Components cannot advertise a version. E.g., ZKF, AMBARI_METRICS, Kerberos
-        ComponentInfo compInfo = ambariMetaInfo.getComponent(
-            stackName, stackVersion, hostComponentStateEntity.getServiceName(),
-            hostComponentStateEntity.getComponentName());
+      ComponentInfo compInfo = ambariMetaInfo.getComponent(
+          stackName, stackVersion, hostComponentStateEntity.getServiceName(),
+          hostComponentStateEntity.getComponentName());
 
-        if (!compInfo.isVersionAdvertised()) {
-          noVersionNeededComponents.add(hostComponentStateEntity);
+      if (!compInfo.isVersionAdvertised()) {
+        // Some Components cannot advertise a version. E.g., ZKF, AMBARI_METRICS, Kerberos
+        noVersionToAdvertise.add(hostComponentStateEntity);
+      } else {
+        if (hostComponentStateEntity.getVersion() == null || hostComponentStateEntity.getVersion().isEmpty() || hostComponentStateEntity.getVersion().equalsIgnoreCase(State.UNKNOWN.toString())) {
+          waitingToAdvertiseVersion.add(hostComponentStateEntity);
+        } else {
+          haveAdvertisedVersion.add(hostComponentStateEntity);
+          versions.add(hostComponentStateEntity.getVersion());
         }
       }
     }
@@ -68,26 +75,33 @@ public class ServiceComponentHostSummary  {
     this(ambariMetaInfo, host, stackId.getStackName(), stackId.getStackVersion());
   }
 
-  public Collection<HostComponentStateEntity> getAllHostComponents() {
-    return allHostComponents;
+  public Collection<HostComponentStateEntity> getHaveAdvertisedVersion() {
+    return haveAdvertisedVersion;
   }
 
-  public Collection<HostComponentStateEntity> getVersionedHostComponents() {
-    return versionedHostComponents;
+  public boolean isUpgradeFinished() {
+    return haveAllComponentsFinishedAdvertisingVersion() && haveSameVersion(getHaveAdvertisedVersion());
   }
 
-  public Collection<HostComponentStateEntity> getNoVersionNeededComponents() {
-    return noVersionNeededComponents;
+  /**
+   * @param currentRepoVersion Repo Version that is CURRENT for this host
+   * @return Return true if multiple component versions are found for this host, or if it does not coincide with the
+   * CURRENT repo version.
+   */
+  public boolean isUpgradeInProgress(String currentRepoVersion) {
+    // Exactly one CURRENT version must exist
+    // We can only detect an upgrade if the Host has at least one component that advertises a version and has done so already
+    // If distinct versions have been advertises, then an upgrade is in progress.
+    // If exactly one version has been advertises, but it doesn't coincide with the CURRENT HostVersion, then an upgrade is in progress.
+    return currentRepoVersion != null && (versions.size() > 1 || (versions.size() == 1 && !versions.iterator().next().equals(currentRepoVersion)));
   }
 
   /**
-   * Determine if all of the components on this host have finished advertising a version, which occurs when all of the
-   * components that advertise a version, plus the components that do not advertise a version, equal the total number
-   * of components.
+   * Determine if all of the components on that need to advertise a version have finished doing so.
    * @return Return a bool indicating if all components that can report a version have done so.
    */
   public boolean haveAllComponentsFinishedAdvertisingVersion() {
-    return allHostComponents.size() == versionedHostComponents.size() + noVersionNeededComponents.size();
+    return waitingToAdvertiseVersion.size() == 0;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 1d13717..adf562b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -162,7 +162,7 @@ public class AmbariManagementControllerTest {
   private static final String PROPERTY_NAME = "hbase.regionserver.msginterval";
   private static final String SERVICE_NAME = "HDFS";
   private static final String FAKE_SERVICE_NAME = "FAKENAGIOS";
-  private static final int STACK_VERSIONS_CNT = 13;
+  private static final int STACK_VERSIONS_CNT = 14;
   private static final int REPOS_CNT = 3;
   private static final int STACKS_CNT = 3;
   private static final int STACK_PROPERTIES_CNT = 103;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
index c21215a..f9e81af 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
@@ -92,13 +92,13 @@ public class StackManagerTest {
   @Test
   public void testGetStacks_count() throws Exception {
     Collection<StackInfo> stacks = stackManager.getStacks();
-    assertEquals(17, stacks.size());
+    assertEquals(18, stacks.size());
   }
 
   @Test
   public void testGetStack_name__count() {
     Collection<StackInfo> stacks = stackManager.getStacks("HDP");
-    assertEquals(13, stacks.size());
+    assertEquals(14, stacks.size());
 
     stacks = stackManager.getStacks("OTHER");
     assertEquals(2, stacks.size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/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 a8b64f8..e444828 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
@@ -56,11 +56,15 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.ClusterVersionDAO;
+import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
+import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+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;
@@ -69,6 +73,7 @@ import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigFactory;
 import org.apache.ambari.server.state.ConfigImpl;
@@ -116,7 +121,11 @@ public class ClusterTest {
   private ConfigFactory configFactory;
   private ConfigGroupFactory configGroupFactory;
   private OrmTestHelper helper;
+  private HostDAO hostDAO;
+  private ClusterVersionDAO clusterVersionDAO;
   private HostVersionDAO hostVersionDAO;
+  private HostComponentStateDAO hostComponentStateDAO;
+  private RepositoryVersionDAO repositoryVersionDAO;
 
   @Singleton
   static class ClusterVersionDAOMock extends ClusterVersionDAO {
@@ -165,8 +174,20 @@ public class ClusterTest {
     configFactory = injector.getInstance(ConfigFactory.class);
     metaInfo = injector.getInstance(AmbariMetaInfo.class);
     helper = injector.getInstance(OrmTestHelper.class);
+    hostDAO = injector.getInstance(HostDAO.class);
+    clusterVersionDAO = injector.getInstance(ClusterVersionDAO.class);
     hostVersionDAO = injector.getInstance(HostVersionDAO.class);
+    hostComponentStateDAO = injector.getInstance(HostComponentStateDAO.class);
+    repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
     metaInfo.init();
+  }
+
+  @After
+  public void teardown() {
+    injector.getInstance(PersistService.class).stop();
+  }
+
+  private void createDefaultCluster() throws Exception {
     clusters.addCluster("c1");
     c1 = clusters.getCluster("c1");
     Assert.assertEquals("c1", c1.getClusterName());
@@ -201,13 +222,282 @@ public class ClusterTest {
     ClusterVersionDAOMock.failOnCurrentVersionState = false;
   }
 
-  @After
-  public void teardown() {
-    injector.getInstance(PersistService.class).stop();
+  public ClusterEntity createDummyData() {
+    ClusterEntity clusterEntity = new ClusterEntity();
+    clusterEntity.setClusterId(1L);
+    clusterEntity.setClusterName("test_cluster1");
+    clusterEntity.setClusterInfo("test_cluster_info1");
+
+    HostEntity host1 = new HostEntity();
+    HostEntity host2 = new HostEntity();
+    HostEntity host3 = new HostEntity();
+
+    host1.setHostName("test_host1");
+    host2.setHostName("test_host2");
+    host3.setHostName("test_host3");
+    host1.setIpv4("192.168.0.1");
+    host2.setIpv4("192.168.0.2");
+    host3.setIpv4("192.168.0.3");
+
+    List<HostEntity> hostEntities = new ArrayList<HostEntity>();
+    hostEntities.add(host1);
+    hostEntities.add(host2);
+
+    clusterEntity.setHostEntities(hostEntities);
+    clusterEntity.setClusterConfigEntities(Collections.EMPTY_LIST);
+    //both sides of relation should be set when modifying in runtime
+    host1.setClusterEntities(Arrays.asList(clusterEntity));
+    host2.setClusterEntities(Arrays.asList(clusterEntity));
+
+    HostStateEntity hostStateEntity1 = new HostStateEntity();
+    hostStateEntity1.setCurrentState(HostState.HEARTBEAT_LOST);
+    hostStateEntity1.setHostEntity(host1);
+    HostStateEntity hostStateEntity2 = new HostStateEntity();
+    hostStateEntity2.setCurrentState(HostState.HEALTHY);
+    hostStateEntity2.setHostEntity(host2);
+    host1.setHostStateEntity(hostStateEntity1);
+    host2.setHostStateEntity(hostStateEntity2);
+
+    ClusterServiceEntity clusterServiceEntity = new ClusterServiceEntity();
+    clusterServiceEntity.setServiceName("HDFS");
+    clusterServiceEntity.setClusterEntity(clusterEntity);
+    clusterServiceEntity.setServiceComponentDesiredStateEntities(
+        Collections.EMPTY_LIST);
+    ServiceDesiredStateEntity stateEntity = mock(ServiceDesiredStateEntity.class);
+    Gson gson = new Gson();
+    when(stateEntity.getDesiredStackVersion()).thenReturn(gson.toJson(new StackId("HDP-0.1"),
+        StackId.class));
+    clusterServiceEntity.setServiceDesiredStateEntity(stateEntity);
+    List<ClusterServiceEntity> clusterServiceEntities = new ArrayList<ClusterServiceEntity>();
+    clusterServiceEntities.add(clusterServiceEntity);
+    clusterEntity.setClusterServiceEntities(clusterServiceEntities);
+    return clusterEntity;
+  }
+
+  private void checkStackVersionState(String stack, String version, RepositoryVersionState state) {
+    Collection<ClusterVersionEntity> allClusterVersions = c1.getAllClusterVersions();
+    for (ClusterVersionEntity entity : allClusterVersions) {
+      if (entity.getRepositoryVersion().getStack().equals(stack)
+          && entity.getRepositoryVersion().getVersion().equals(version)) {
+        assertEquals(state, entity.getState());
+      }
+    }
+  }
+
+  private void assertStateException(String stack, String version, RepositoryVersionState transitionState,
+                                    RepositoryVersionState stateAfter) {
+    try {
+      c1.transitionClusterVersion(stack, version, transitionState);
+      Assert.fail();
+    } catch (AmbariException e) {}
+    checkStackVersionState(stack, version, stateAfter);
+    assertNotNull(c1.getCurrentClusterVersion());
+  }
+
+  /**
+   * For Rolling Upgrades, create a cluster with the following components
+   * HDFS: NameNode, DataNode, HDFS Client
+   * ZK: Zookeeper Server, Zookeeper Monitor
+   * Ganglia: Ganglia Server, Ganglia Monitor
+   *
+   * Further, 3 hosts will be added.
+   * Finally, verify that only the Ganglia components do not need to advertise a version.
+   * @param clusterName Cluster Name
+   * @param stackId Stack to set for the cluster
+   * @param hostAttributes Host attributes to use for 3 hosts (h-1, h-2, h-3)
+   * @throws Exception
+   * @return Cluster that was created
+   */
+  private Cluster createClusterForRU(String clusterName, StackId stackId, Map<String, String> hostAttributes) throws Exception {
+    clusters.addCluster(clusterName);
+    Cluster cluster = clusters.getCluster(clusterName);
+    Assert.assertEquals(clusterName, cluster.getClusterName());
+    Assert.assertEquals(1, cluster.getClusterId());
+
+    // Add Hosts
+    List<String> hostNames = new ArrayList<String>() {{ add("h-1"); add("h-2"); add("h-3"); }};
+    for(String hostName : hostNames) {
+      addHost(hostName, hostAttributes);
+    }
+
+    // Add stack and map Hosts to cluster
+    cluster.setDesiredStackVersion(stackId);
+    cluster.setCurrentStackVersion(stackId);
+    for(String hostName : hostNames) {
+      clusters.mapHostToCluster(hostName, clusterName);
+    }
+
+    // Add Services
+    Service s1 = serviceFactory.createNew(cluster, "HDFS");
+    Service s2 = serviceFactory.createNew(cluster, "ZOOKEEPER");
+    Service s3 = serviceFactory.createNew(cluster, "GANGLIA");
+    cluster.addService(s1);
+    cluster.addService(s2);
+    cluster.addService(s3);
+    s1.persist();
+    s2.persist();
+    s3.persist();
+
+    // Add HDFS components
+    ServiceComponent sc1CompA = serviceComponentFactory.createNew(s1, "NAMENODE");
+    ServiceComponent sc1CompB = serviceComponentFactory.createNew(s1, "DATANODE");
+    ServiceComponent sc1CompC = serviceComponentFactory.createNew(s1, "HDFS_CLIENT");
+    s1.addServiceComponent(sc1CompA);
+    s1.addServiceComponent(sc1CompB);
+    s1.addServiceComponent(sc1CompC);
+    sc1CompA.persist();
+    sc1CompB.persist();
+    sc1CompC.persist();
+
+    // Add ZK
+    ServiceComponent sc2CompA = serviceComponentFactory.createNew(s2, "ZOOKEEPER_SERVER");
+    ServiceComponent sc2CompB = serviceComponentFactory.createNew(s2, "ZOOKEEPER_CLIENT");
+    s2.addServiceComponent(sc2CompA);
+    s2.addServiceComponent(sc2CompB);
+    sc2CompA.persist();
+    sc2CompB.persist();
+
+    // Add Ganglia
+    ServiceComponent sc3CompA = serviceComponentFactory.createNew(s3, "GANGLIA_SERVER");
+    ServiceComponent sc3CompB = serviceComponentFactory.createNew(s3, "GANGLIA_MONITOR");
+    s3.addServiceComponent(sc3CompA);
+    s3.addServiceComponent(sc3CompB);
+    sc3CompA.persist();
+    sc3CompB.persist();
+
+    // Host 1 will have all components
+    ServiceComponentHost schHost1Serv1CompA = serviceComponentHostFactory.createNew(sc1CompA, "h-1");
+    ServiceComponentHost schHost1Serv1CompB = serviceComponentHostFactory.createNew(sc1CompB, "h-1");
+    ServiceComponentHost schHost1Serv1CompC = serviceComponentHostFactory.createNew(sc1CompC, "h-1");
+    ServiceComponentHost schHost1Serv2CompA = serviceComponentHostFactory.createNew(sc2CompA, "h-1");
+    ServiceComponentHost schHost1Serv2CompB = serviceComponentHostFactory.createNew(sc2CompB, "h-1");
+    ServiceComponentHost schHost1Serv3CompA = serviceComponentHostFactory.createNew(sc3CompA, "h-1");
+    ServiceComponentHost schHost1Serv3CompB = serviceComponentHostFactory.createNew(sc3CompB, "h-1");
+    sc1CompA.addServiceComponentHost(schHost1Serv1CompA);
+    sc1CompB.addServiceComponentHost(schHost1Serv1CompB);
+    sc1CompC.addServiceComponentHost(schHost1Serv1CompC);
+    sc2CompA.addServiceComponentHost(schHost1Serv2CompA);
+    sc2CompB.addServiceComponentHost(schHost1Serv2CompB);
+    sc3CompA.addServiceComponentHost(schHost1Serv3CompA);
+    sc3CompB.addServiceComponentHost(schHost1Serv3CompB);
+    schHost1Serv1CompA.persist();
+    schHost1Serv1CompB.persist();
+    schHost1Serv1CompC.persist();
+    schHost1Serv2CompA.persist();
+    schHost1Serv2CompB.persist();
+    schHost1Serv3CompA.persist();
+    schHost1Serv3CompB.persist();
+
+    // Host 2 will have ZK_CLIENT and GANGLIA_MONITOR
+    ServiceComponentHost schHost2Serv2CompB = serviceComponentHostFactory.createNew(sc2CompB, "h-2");
+    ServiceComponentHost schHost2Serv3CompB = serviceComponentHostFactory.createNew(sc3CompB, "h-2");
+    sc2CompB.addServiceComponentHost(schHost2Serv2CompB);
+    sc3CompB.addServiceComponentHost(schHost2Serv3CompB);
+    schHost2Serv2CompB.persist();
+    schHost2Serv3CompB.persist();
+
+    // Host 3 will have GANGLIA_MONITOR
+    ServiceComponentHost schHost3Serv3CompB = serviceComponentHostFactory.createNew(sc3CompB, "h-3");
+    sc3CompB.addServiceComponentHost(schHost3Serv3CompB);
+    schHost3Serv3CompB.persist();
+
+    // Verify count of components
+    List<ServiceComponentHost> scHost1 = cluster.getServiceComponentHosts("h-1");
+    Assert.assertEquals(7, scHost1.size());
+
+    List<ServiceComponentHost> scHost2 = cluster.getServiceComponentHosts("h-2");
+    Assert.assertEquals(2, scHost2.size());
+
+    List<ServiceComponentHost> scHost3 = cluster.getServiceComponentHosts("h-3");
+    Assert.assertEquals(1, scHost3.size());
+
+    //<editor-fold desc="Validate Version Advertised">
+    /*
+    For some reason this still uses the metainfo.xml files for these services
+    from HDP-2.0.5 stack instead of the provided Stack Id
+    */
+    HashMap<String, Set<String>> componentsThatAdvertiseVersion = new HashMap<String, Set<String>>();
+    HashMap<String, Set<String>> componentsThatDontAdvertiseVersion = new HashMap<String, Set<String>>();
+
+    Set<String> hdfsComponents = new HashSet<String>() {{ add("NAMENODE"); add("DATANODE"); add("HDFS_CLIENT"); }};
+    Set<String> zkComponents = new HashSet<String>() {{ add("ZOOKEEPER_SERVER"); add("ZOOKEEPER_CLIENT"); }};
+    Set<String> gangliaComponents = new HashSet<String>() {{ add("GANGLIA_SERVER"); add("GANGLIA_MONITOR"); }};
+
+    componentsThatAdvertiseVersion.put("HDFS", hdfsComponents);
+    componentsThatAdvertiseVersion.put("ZOOKEEPER", zkComponents);
+    componentsThatDontAdvertiseVersion.put("GANGLIA", gangliaComponents);
+
+    for(String service : componentsThatAdvertiseVersion.keySet())  {
+      Set<String> components = componentsThatAdvertiseVersion.get(service);
+      for(String componentName : components) {
+        ComponentInfo component = metaInfo.getComponent(stackId.getStackName(), stackId.getStackVersion(), service, componentName);
+        Assert.assertTrue(component.isVersionAdvertised());
+      }
+    }
+
+    for(String service : componentsThatDontAdvertiseVersion.keySet())  {
+      Set<String> components = componentsThatDontAdvertiseVersion.get(service);
+      for(String componentName : components) {
+        ComponentInfo component = metaInfo.getComponent(stackId.getStackName(), stackId.getStackVersion(), service, componentName);
+        Assert.assertFalse(component.isVersionAdvertised());
+      }
+    }
+    //</editor-fold>
+
+    return cluster;
+  }
+
+  /**
+   * Add a host to the system with the provided attributes.
+   * @param hostName Host Name
+   * @param hostAttributes Host Attributes
+   * @throws Exception
+   */
+  private void addHost(String hostName, Map<String, String> hostAttributes) throws Exception {
+    clusters.addHost(hostName);
+    Host host = clusters.getHost(hostName);
+    host.setIPv4("ipv4");
+    host.setIPv6("ipv6");
+    host.setHostAttributes(hostAttributes);
+    host.persist();
+  }
+
+  /**
+   * For the provided collection of HostComponentStates, set the version to {@paramref version} if the Component
+   * can advertise a version. Then, simulate the {@link org.apache.ambari.server.events.listeners.upgrade.StackVersionListener}
+   * by calling methods to transition the HostVersion, and recalculate the ClusterVersion.
+   * @param stackId Stack ID to retrieve the ComponentInfo
+   * @param version Version to set
+   * @param cluster Cluster to retrieve services from
+   * @param hostComponentStates Collection to set the version for
+   * @throws Exception
+   */
+  private void simulateStackVersionListener(StackId stackId, String version, Cluster cluster, List<HostComponentStateEntity> hostComponentStates) throws Exception {
+    for(int i = 0; i < hostComponentStates.size(); i++) {
+      HostComponentStateEntity hce = hostComponentStates.get(i);
+      ComponentInfo compInfo = metaInfo.getComponent(
+          stackId.getStackName(), stackId.getStackVersion(),
+          hce.getServiceName(),
+          hce.getComponentName());
+
+      if (compInfo.isVersionAdvertised()) {
+        hce.setVersion(version);
+        hostComponentStateDAO.merge(hce);
+      }
+
+      // Simulate the StackVersionListener during the installation
+      Service svc = cluster.getService(hce.getServiceName());
+      ServiceComponent svcComp = svc.getServiceComponent(hce.getComponentName());
+      ServiceComponentHost scHost = svcComp.getServiceComponentHost(hce.getHostName());
+
+      scHost.recalculateHostVersionState();
+      cluster.recalculateClusterVersionState(version);
+    }
   }
 
   @Test
-  public void testAddHost() throws AmbariException {
+  public void testAddHost() throws Exception {
+    createDefaultCluster();
     clusters.addHost("h3");
 
     try {
@@ -217,25 +507,29 @@ public class ClusterTest {
     catch (AmbariException e) {
       // Expected
     }
-
   }
 
-
   @Test
-  public void testGetHostState() throws AmbariException {
+  public void testGetHostState() throws Exception {
+    createDefaultCluster();
+    
     Assert.assertEquals(HostState.INIT, clusters.getHost("h1").getState());
   }
 
   @Test
-  public void testSetHostState() throws AmbariException {
+  public void testSetHostState() throws Exception {
+    createDefaultCluster();
+    
     clusters.getHost("h1").setState(HostState.HEARTBEAT_LOST);
     Assert.assertEquals(HostState.HEARTBEAT_LOST,
         clusters.getHost("h1").getState());
   }
 
   @Test
-  public void testHostEvent() throws AmbariException,
+  public void testHostEvent() throws Exception,
       InvalidStateTransitionException {
+    createDefaultCluster();
+    
     HostInfo hostInfo = new HostInfo();
     hostInfo.setHostName("h1");
     hostInfo.setInterfaces("fip_4");
@@ -282,7 +576,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testBasicClusterSetup() throws AmbariException {
+  public void testBasicClusterSetup() throws Exception {
+    createDefaultCluster();
+
     String clusterName = "c2";
 
     try {
@@ -311,7 +607,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testAddAndGetServices() throws AmbariException {
+  public void testAddAndGetServices() throws Exception {
+    createDefaultCluster();
+
     // TODO write unit tests for
     // public void addService(Service service) throws AmbariException;
     // public Service getService(String serviceName) throws AmbariException;
@@ -353,9 +651,10 @@ public class ClusterTest {
     Assert.assertTrue(services.containsKey("MAPREDUCE"));
   }
 
-
   @Test
-  public void testGetServiceComponentHosts() throws AmbariException {
+  public void testGetServiceComponentHosts() throws Exception {
+    createDefaultCluster();
+
     // TODO write unit tests
     // public List<ServiceComponentHost> getServiceComponentHosts(String hostname);
 
@@ -397,9 +696,9 @@ public class ClusterTest {
     Assert.assertEquals(2, scHosts.size());
   }
 
-
   @Test
-  public void testGetAndSetConfigs() {
+  public void testGetAndSetConfigs() throws Exception {
+    createDefaultCluster();
 
     Map<String, Map<String, String>> c1PropAttributes = new HashMap<String, Map<String,String>>();
     c1PropAttributes.put("final", new HashMap<String, String>());
@@ -439,6 +738,8 @@ public class ClusterTest {
 
   @Test
   public void testDesiredConfigs() throws Exception {
+    createDefaultCluster();
+
     Config config1 = configFactory.createNew(c1, "global",
         new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
     config1.setTag("version1");
@@ -494,58 +795,6 @@ public class ClusterTest {
     Assert.assertEquals("Expect one host-level override", 1, dc.getHostOverrides().size());
   }
 
-  public ClusterEntity createDummyData() {
-    ClusterEntity clusterEntity = new ClusterEntity();
-    clusterEntity.setClusterId(1L);
-    clusterEntity.setClusterName("test_cluster1");
-    clusterEntity.setClusterInfo("test_cluster_info1");
-
-    HostEntity host1 = new HostEntity();
-    HostEntity host2 = new HostEntity();
-    HostEntity host3 = new HostEntity();
-
-    host1.setHostName("test_host1");
-    host2.setHostName("test_host2");
-    host3.setHostName("test_host3");
-    host1.setIpv4("192.168.0.1");
-    host2.setIpv4("192.168.0.2");
-    host3.setIpv4("192.168.0.3");
-
-    List<HostEntity> hostEntities = new ArrayList<HostEntity>();
-    hostEntities.add(host1);
-    hostEntities.add(host2);
-
-    clusterEntity.setHostEntities(hostEntities);
-    clusterEntity.setClusterConfigEntities(Collections.EMPTY_LIST);
-    //both sides of relation should be set when modifying in runtime
-    host1.setClusterEntities(Arrays.asList(clusterEntity));
-    host2.setClusterEntities(Arrays.asList(clusterEntity));
-
-    HostStateEntity hostStateEntity1 = new HostStateEntity();
-    hostStateEntity1.setCurrentState(HostState.HEARTBEAT_LOST);
-    hostStateEntity1.setHostEntity(host1);
-    HostStateEntity hostStateEntity2 = new HostStateEntity();
-    hostStateEntity2.setCurrentState(HostState.HEALTHY);
-    hostStateEntity2.setHostEntity(host2);
-    host1.setHostStateEntity(hostStateEntity1);
-    host2.setHostStateEntity(hostStateEntity2);
-
-    ClusterServiceEntity clusterServiceEntity = new ClusterServiceEntity();
-    clusterServiceEntity.setServiceName("HDFS");
-    clusterServiceEntity.setClusterEntity(clusterEntity);
-    clusterServiceEntity.setServiceComponentDesiredStateEntities(
-        Collections.EMPTY_LIST);
-    ServiceDesiredStateEntity stateEntity = mock(ServiceDesiredStateEntity.class);
-    Gson gson = new Gson();
-    when(stateEntity.getDesiredStackVersion()).thenReturn(gson.toJson(new StackId("HDP-0.1"),
-        StackId.class));
-    clusterServiceEntity.setServiceDesiredStateEntity(stateEntity);
-    List<ClusterServiceEntity> clusterServiceEntities = new ArrayList<ClusterServiceEntity>();
-    clusterServiceEntities.add(clusterServiceEntity);
-    clusterEntity.setClusterServiceEntities(clusterServiceEntities);
-    return clusterEntity;
-  }
-
   @Test
   public void testClusterRecovery() throws AmbariException {
     ClusterEntity entity = createDummyData();
@@ -560,9 +809,10 @@ public class ClusterTest {
     Assert.assertNotNull(services.get("HDFS"));
   }
 
-
   @Test
-  public void testConvertToResponse() throws AmbariException {
+  public void testConvertToResponse() throws Exception {
+    createDefaultCluster();
+
     ClusterResponse r = c1.convertToResponse();
     Assert.assertEquals(c1.getClusterId(), r.getClusterId().longValue());
     Assert.assertEquals(c1.getClusterName(), r.getClusterName());
@@ -615,6 +865,8 @@ public class ClusterTest {
 
   @Test
   public void testDeleteService() throws Exception {
+    createDefaultCluster();
+
     c1.addService("MAPREDUCE").persist();
 
     Service hdfs = c1.addService("HDFS");
@@ -636,6 +888,8 @@ public class ClusterTest {
 
   @Test
   public void testGetHostsDesiredConfigs() throws Exception {
+    createDefaultCluster();
+
     Host host1 = clusters.getHost("h1");
 
     Map<String, Map<String, String>> propAttributes = new HashMap<String, Map<String,String>>();
@@ -663,7 +917,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testProvisioningState() throws AmbariException {
+  public void testProvisioningState() throws Exception {
+    createDefaultCluster();
+
     c1.setProvisioningState(State.INIT);
     Assert.assertEquals(State.INIT,
         c1.getProvisioningState());
@@ -674,7 +930,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testServiceConfigVersions() throws AmbariException {
+  public void testServiceConfigVersions() throws Exception {
+    createDefaultCluster();
+
     Config config1 = configFactory.createNew(c1, "hdfs-site",
       new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
     config1.setTag("version1");
@@ -730,12 +988,12 @@ public class ClusterTest {
     Assert.assertEquals("c1", hdfsResponse.getClusterName());
     Assert.assertEquals("admin", hdfsResponse.getUserName());
     assertEquals(Long.valueOf(3), hdfsResponse.getVersion());
-
-
   }
 
   @Test
-  public void testSingleServiceVersionForMultipleConfigs() {
+  public void testSingleServiceVersionForMultipleConfigs() throws Exception {
+    createDefaultCluster();
+
     Config config1 = configFactory.createNew(c1, "hdfs-site",
       new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
     config1.setTag("version1");
@@ -765,12 +1023,12 @@ public class ClusterTest {
     Map<String, Collection<ServiceConfigVersionResponse>> activeServiceConfigVersions =
       c1.getActiveServiceConfigVersions();
     Assert.assertEquals(1, activeServiceConfigVersions.size());
-
-
   }
 
   @Test
-  public void testServiceConfigVersionsForGroups() throws AmbariException {
+  public void testServiceConfigVersionsForGroups() throws Exception {
+    createDefaultCluster();
+
     Config config1 = configFactory.createNew(c1, "hdfs-site",
       new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
     config1.setTag("version1");
@@ -862,31 +1120,12 @@ public class ClusterTest {
     Assert.assertEquals("Three service config versions should be active, for default and test groups",
         3, activeServiceConfigVersions.get("HDFS").size());
     assertEquals("Five total scvs", 5, c1.getServiceConfigVersions().size());
-
-  }
-
-  private void checkStackVersionState(String stack, String version, RepositoryVersionState state) {
-    Collection<ClusterVersionEntity> allClusterVersions = c1.getAllClusterVersions();
-    for (ClusterVersionEntity entity : allClusterVersions) {
-      if (entity.getRepositoryVersion().getStack().equals(stack)
-          && entity.getRepositoryVersion().getVersion().equals(version)) {
-        assertEquals(state, entity.getState());
-      }
-    }
-  }
-
-  private void assertStateException(String stack, String version, RepositoryVersionState transitionState,
-                                    RepositoryVersionState stateAfter) {
-    try {
-      c1.transitionClusterVersion(stack, version, transitionState);
-      Assert.fail();
-    } catch (AmbariException e) {}
-    checkStackVersionState(stack, version, stateAfter);
-    assertNotNull(c1.getCurrentClusterVersion());
   }
 
   @Test
-  public void testTransitionClusterVersion() throws AmbariException {
+  public void testTransitionClusterVersion() throws Exception {
+    createDefaultCluster();
+
     String stack = "HDP";
     String version = "0.2";
 
@@ -972,7 +1211,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testTransitionClusterVersionTransactionFail() throws AmbariException {
+  public void testTransitionClusterVersionTransactionFail() throws Exception {
+    createDefaultCluster();
+
     helper.getOrCreateRepositoryVersion("HDP", "0.2");
     c1.createClusterVersion("HDP", "0.2", "admin", RepositoryVersionState.INSTALLING);
     c1.transitionClusterVersion("HDP", "0.2", RepositoryVersionState.INSTALLED);
@@ -993,7 +1234,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testInferHostVersions() throws AmbariException {
+  public void testInferHostVersions() throws Exception {
+    createDefaultCluster();
+
     helper.getOrCreateRepositoryVersion("HDP", "0.2");
     c1.createClusterVersion("HDP", "0.2", "admin", RepositoryVersionState.INSTALLING);
     ClusterVersionEntity entityHDP2 = null;
@@ -1044,7 +1287,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testRecalculateClusterVersionState() throws AmbariException {
+  public void testRecalculateClusterVersionState() throws Exception {
+    createDefaultCluster();
+
     Host h1 = clusters.getHost("h1");
     h1.setState(HostState.HEALTHY);
 
@@ -1134,7 +1379,9 @@ public class ClusterTest {
   }
 
   @Test
-  public void testRecalculateAllClusterVersionStates() throws AmbariException {
+  public void testRecalculateAllClusterVersionStates() throws Exception {
+    createDefaultCluster();
+
     Host h1 = clusters.getHost("h1");
     h1.setState(HostState.HEALTHY);
 
@@ -1172,13 +1419,201 @@ public class ClusterTest {
     checkStackVersionState(stackId.getStackId(), "1.0-2086", RepositoryVersionState.CURRENT);
   }
 
+  /**
+   * Comprehensive test for transitionHostVersion and recalculateClusterVersion.
+   * It creates a cluster with 3 hosts and 3 services, one of which does not advertise a version.
+   * It then verifies that all 3 hosts have a version of CURRENT, and so does the cluster.
+   * It then adds one more host with a component, so its HostVersion will initialize in CURRENT.
+   * Next, it distributes a repo so that it is INSTALLED on the 4 hosts.
+   * It then adds one more host, whose HostVersion will be OUT_OF_SYNC for the new repo.
+   * After redistributing bits again, it simulates an RU.
+   * Finally, some of the hosts will end up with a HostVersion in UPGRADED, and others still in INSTALLED.
+   * @throws Exception
+   */
+  @Test
+  public void testTransitionHostVersionAdvanced() throws Exception {
+    String clusterName = "c1";
+    String v1 = "2.2.0-123";
+    StackId stackId = new StackId("HDP-2.2.0");
+
+    Map<String, String> hostAttributes = new HashMap<String, String>();
+    hostAttributes.put("os_family", "redhat");
+    hostAttributes.put("os_release_version", "5.9");
+
+    Cluster cluster = createClusterForRU(clusterName, stackId, hostAttributes);
+
+    // Begin install by starting to advertise versions
+    // Set the version for the HostComponentState objects
+    int versionedComponentCount = 0;
+    List<HostComponentStateEntity> hostComponentStates = hostComponentStateDAO.findAll();
+    for(int i = 0; i < hostComponentStates.size(); i++) {
+      HostComponentStateEntity hce = hostComponentStates.get(i);
+      ComponentInfo compInfo = metaInfo.getComponent(
+          stackId.getStackName(), stackId.getStackVersion(),
+          hce.getServiceName(),
+          hce.getComponentName());
+
+      if (compInfo.isVersionAdvertised()) {
+        hce.setVersion(v1);
+        hostComponentStateDAO.merge(hce);
+        versionedComponentCount++;
+      }
+
+      // Simulate the StackVersionListener during the installation of the first Stack Version
+      Service svc = cluster.getService(hce.getServiceName());
+      ServiceComponent svcComp = svc.getServiceComponent(hce.getComponentName());
+      ServiceComponentHost scHost = svcComp.getServiceComponentHost(hce.getHostName());
+
+      scHost.recalculateHostVersionState();
+      cluster.recalculateClusterVersionState(v1);
+
+      Collection<ClusterVersionEntity> clusterVersions = cluster.getAllClusterVersions();
+
+      if (versionedComponentCount > 0) {
+        // On the first component with a version, a RepoVersion should have been created
+        RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stackId.getStackId(), v1);
+        Assert.assertNotNull(repositoryVersion);
+        Assert.assertTrue(clusterVersions != null && clusterVersions.size() == 1);
+
+        // First component to report a version should cause the ClusterVersion to go to UPGRADING
+        if (versionedComponentCount == 1 && i < (hostComponentStates.size() - 1)) {
+          Assert.assertEquals(clusterVersions.iterator().next().getState(), RepositoryVersionState.UPGRADING);
+        }
+
+        // Last component to report a version should cause the ClusterVersion to go to CURRENT
+        if (i == hostComponentStates.size() - 1) {
+          Assert.assertEquals(clusterVersions.iterator().next().getState(), RepositoryVersionState.CURRENT);
+        }
+      }
+    }
+
+    // Add another Host with components ZK Server, ZK Client, and Ganglia Monitor.
+    // This host should get a HostVersion in CURRENT, and the ClusterVersion should stay in CURRENT
+    addHost("h-4", hostAttributes);
+    clusters.mapHostToCluster("h-4", clusterName);
+
+    Service svc2 = cluster.getService("ZOOKEEPER");
+    Service svc3 = cluster.getService("GANGLIA");
+
+    ServiceComponent sc2CompA = svc2.getServiceComponent("ZOOKEEPER_SERVER");
+    ServiceComponent sc2CompB = svc2.getServiceComponent("ZOOKEEPER_CLIENT");
+    ServiceComponent sc3CompB = svc3.getServiceComponent("GANGLIA_MONITOR");
+
+    ServiceComponentHost schHost4Serv2CompA = serviceComponentHostFactory.createNew(sc2CompA, "h-4");
+    ServiceComponentHost schHost4Serv2CompB = serviceComponentHostFactory.createNew(sc2CompB, "h-4");
+    ServiceComponentHost schHost4Serv3CompB = serviceComponentHostFactory.createNew(sc3CompB, "h-4");
+    sc2CompA.addServiceComponentHost(schHost4Serv2CompA);
+    sc2CompB.addServiceComponentHost(schHost4Serv2CompB);
+    sc3CompB.addServiceComponentHost(schHost4Serv3CompB);
+    schHost4Serv2CompA.persist();
+    schHost4Serv2CompB.persist();
+    schHost4Serv3CompB.persist();
+
+    simulateStackVersionListener(stackId, v1, cluster, hostComponentStateDAO.findByHost("h-4"));
+
+    Collection<HostVersionEntity> hostVersions = hostVersionDAO.findAll();
+    Assert.assertEquals(hostVersions.size(), clusters.getHosts().size());
+    HostVersionEntity h4Version1 = hostVersionDAO.findByClusterStackVersionAndHost(clusterName, stackId.getStackId(), v1, "h-4");
+    Assert.assertNotNull(h4Version1);
+    Assert.assertEquals(h4Version1.getState(), RepositoryVersionState.CURRENT);
+
+    // Distribute bits for a new repo
+    String v2 = "2.2.0-456";
+    RepositoryVersionEntity rv2 = helper.getOrCreateRepositoryVersion(stackId.getStackId(), v2);
+    for(String hostName : clusters.getHostsForCluster(clusterName).keySet()) {
+      HostEntity host = hostDAO.findByName(hostName);
+      HostVersionEntity hve = new HostVersionEntity(hostName, rv2, RepositoryVersionState.INSTALLED);
+      hve.setHostEntity(host);
+      hostVersionDAO.create(hve);
+    }
+    cluster.createClusterVersion(stackId.getStackId(), v2, "admin", RepositoryVersionState.INSTALLING);
+    cluster.transitionClusterVersion(stackId.getStackId(), v2, RepositoryVersionState.INSTALLED);
+
+    ClusterVersionEntity cv2 = clusterVersionDAO.findByClusterAndStackAndVersion(clusterName, stackId.getStackId(), v2);
+    Assert.assertNotNull(cv2);
+    Assert.assertEquals(cv2.getState(), RepositoryVersionState.INSTALLED);
+
+    // Add one more Host, with only Ganglia on it. It should have a HostVersion in OUT_OF_SYNC for v2
+    addHost("h-5", hostAttributes);
+    clusters.mapHostToCluster("h-5", clusterName);
+    ServiceComponentHost schHost5Serv3CompB = serviceComponentHostFactory.createNew(sc3CompB, "h-5");
+    sc3CompB.addServiceComponentHost(schHost5Serv3CompB);
+    schHost5Serv3CompB.persist();
+
+    // Host 5 will be in OUT_OF_SYNC, so redistribute bits to it so that it reaches a state of INSTALLED
+    HostVersionEntity h5Version2 = hostVersionDAO.findByClusterStackVersionAndHost(clusterName, stackId.getStackId(), v2, "h-5");
+    Assert.assertNotNull(h5Version2);
+    Assert.assertEquals(h5Version2.getState(), RepositoryVersionState.OUT_OF_SYNC);
+
+    h5Version2.setState(RepositoryVersionState.INSTALLED);
+    hostVersionDAO.merge(h5Version2);
+
+    // Perform an RU.
+    // Verify that on first component with the new version, the ClusterVersion transitions to UPGRADING.
+    // For hosts with only components that advertise a version, they HostVersion should be in UPGRADING.
+    // For the remaining hosts, the HostVersion should stay in INSTALLED.
+    versionedComponentCount = 0;
+    hostComponentStates = hostComponentStateDAO.findAll();
+    for(int i = 0; i < hostComponentStates.size(); i++) {
+      HostComponentStateEntity hce = hostComponentStates.get(i);
+      ComponentInfo compInfo = metaInfo.getComponent(
+          stackId.getStackName(), stackId.getStackVersion(),
+          hce.getServiceName(),
+          hce.getComponentName());
+
+      if (compInfo.isVersionAdvertised()) {
+        hce.setVersion(v2);
+        hostComponentStateDAO.merge(hce);
+        versionedComponentCount++;
+      }
+
+      // Simulate the StackVersionListener during the installation of the first Stack Version
+      Service svc = cluster.getService(hce.getServiceName());
+      ServiceComponent svcComp = svc.getServiceComponent(hce.getComponentName());
+      ServiceComponentHost scHost = svcComp.getServiceComponentHost(hce.getHostName());
+
+      scHost.recalculateHostVersionState();
+      cluster.recalculateClusterVersionState(v2);
+
+      Collection<ClusterVersionEntity> clusterVersions = cluster.getAllClusterVersions();
+
+      if (versionedComponentCount > 0) {
+        // On the first component with a version, a RepoVersion should have been created
+        RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByStackAndVersion(stackId.getStackId(), v2);
+        Assert.assertNotNull(repositoryVersion);
+        Assert.assertTrue(clusterVersions != null && clusterVersions.size() == 2);
+
+        // First component to report a version should cause the ClusterVersion to go to UPGRADING
+        if (versionedComponentCount == 1 && i < (hostComponentStates.size() - 1)) {
+          cv2 = clusterVersionDAO.findByClusterAndStackAndVersion(clusterName, stackId.getStackId(), v2);
+          Assert.assertEquals(cv2.getState(), RepositoryVersionState.UPGRADING);
+        }
+      }
+    }
+
+    // Last component to report a version should still keep the ClusterVersion in UPGRADING because
+    // hosts 3 and 5 only have Ganglia and the HostVersion will remain in INSTALLED
+    cv2 = clusterVersionDAO.findByClusterAndStackAndVersion(clusterName, stackId.getStackId(), v2);
+    Assert.assertEquals(cv2.getState(), RepositoryVersionState.UPGRADING);
+
+    Collection<HostVersionEntity> v2HostVersions = hostVersionDAO.findByClusterStackAndVersion(clusterName, stackId.getStackId(), v2);
+    Assert.assertEquals(v2HostVersions.size(), clusters.getHostsForCluster(clusterName).size());
+    for (HostVersionEntity hve : v2HostVersions) {
+      if (hve.getHostName().equals("h-3") || hve.getHostName().equals("h-5")) {
+        Assert.assertEquals(hve.getState(), RepositoryVersionState.INSTALLED);
+      } else {
+        Assert.assertEquals(hve.getState(), RepositoryVersionState.UPGRADED);
+      }
+    }
+  }
+
   @Test
   public void testTransitionNonReportableHost() throws Exception {
-    String clusterName = "c2";
+    String clusterName = "c1";
     clusters.addCluster(clusterName);
-    Cluster c2 = clusters.getCluster(clusterName);
-    Assert.assertEquals(clusterName, c2.getClusterName());
-    Assert.assertEquals(2, c2.getClusterId());
+    Cluster c1 = clusters.getCluster(clusterName);
+    Assert.assertEquals(clusterName, c1.getClusterName());
+    Assert.assertEquals(1, c1.getClusterId());
 
     clusters.addHost("h-1");
     clusters.addHost("h-2");
@@ -1196,41 +1631,40 @@ public class ClusterTest {
       h.persist();
     }
 
-
     String v1 = "2.0.5-1";
     String v2 = "2.0.5-2";
     StackId stackId = new StackId("HDP-2.0.5");
-    c2.setDesiredStackVersion(stackId);
+    c1.setDesiredStackVersion(stackId);
     RepositoryVersionEntity rve1 = helper.getOrCreateRepositoryVersion(stackId.getStackName(), v1);
     RepositoryVersionEntity rve2 = helper.getOrCreateRepositoryVersion(stackId.getStackName(), v2);
 
-    c2.setCurrentStackVersion(stackId);
-    c2.createClusterVersion(stackId.getStackName(), v1, "admin", RepositoryVersionState.UPGRADING);
-    c2.transitionClusterVersion(stackId.getStackName(), v1, RepositoryVersionState.CURRENT);
+    c1.setCurrentStackVersion(stackId);
+    c1.createClusterVersion(stackId.getStackName(), v1, "admin", RepositoryVersionState.UPGRADING);
+    c1.transitionClusterVersion(stackId.getStackName(), v1, RepositoryVersionState.CURRENT);
 
-    clusters.mapHostToCluster("h-1", "c2");
-    clusters.mapHostToCluster("h-2", "c2");
-    clusters.mapHostToCluster("h-3", "c2");
+    clusters.mapHostToCluster("h-1", clusterName);
+    clusters.mapHostToCluster("h-2", clusterName);
+    clusters.mapHostToCluster("h-3", clusterName);
     ClusterVersionDAOMock.failOnCurrentVersionState = false;
 
-    Service service = c2.addService("ZOOKEEPER");
+    Service service = c1.addService("ZOOKEEPER");
     ServiceComponent sc = service.addServiceComponent("ZOOKEEPER_SERVER");
     sc.addServiceComponentHost("h-1");
     sc.addServiceComponentHost("h-2");
 
-    service = c2.addService("SQOOP");
+    service = c1.addService("SQOOP");
     sc = service.addServiceComponent("SQOOP");
     sc.addServiceComponentHost("h-3");
 
     List<HostVersionEntity> entities = hostVersionDAO.findByClusterAndHost(clusterName, "h-3");
     assertTrue("Expected no host versions", null == entities || 0 == entities.size());
 
-    c2.createClusterVersion(stackId.getStackName(), v2, "admin", RepositoryVersionState.INSTALLING);
-    c2.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.INSTALLED);
-    c2.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.UPGRADING);
-    c2.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.UPGRADED);
+    c1.createClusterVersion(stackId.getStackName(), v2, "admin", RepositoryVersionState.INSTALLING);
+    c1.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.INSTALLED);
+    c1.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.UPGRADING);
+    c1.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.UPGRADED);
 
-    c2.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.CURRENT);
+    c1.transitionClusterVersion(stackId.getStackName(), v2, RepositoryVersionState.CURRENT);
 
     entities = hostVersionDAO.findByClusterAndHost(clusterName, "h-3");
 
@@ -1244,11 +1678,11 @@ public class ClusterTest {
      * and we add a new host to cluster. On a new host, both CURRENT and OUT_OF_SYNC host
      * versions should be present
      */
-    String clusterName = "c2";
+    String clusterName = "c1";
     clusters.addCluster(clusterName);
-    final Cluster c2 = clusters.getCluster(clusterName);
-    Assert.assertEquals(clusterName, c2.getClusterName());
-    Assert.assertEquals(2, c2.getClusterId());
+    final Cluster c1 = clusters.getCluster(clusterName);
+    Assert.assertEquals(clusterName, c1.getClusterName());
+    Assert.assertEquals(1, c1.getClusterId());
 
     clusters.addHost("h-1");
     clusters.addHost("h-2");
@@ -1270,30 +1704,30 @@ public class ClusterTest {
     String v1 = "2.0.5-1";
     String v2 = "2.0.5-2";
     StackId stackId = new StackId("HDP-2.0.5");
-    c2.setDesiredStackVersion(stackId);
+    c1.setDesiredStackVersion(stackId);
     RepositoryVersionEntity rve1 = helper.getOrCreateRepositoryVersion(stackId.getStackId()
             , v1);
     RepositoryVersionEntity rve2 = helper.getOrCreateRepositoryVersion(stackId.getStackId(), v2);
 
-    c2.setCurrentStackVersion(stackId);
-    c2.createClusterVersion(stackId.getStackId(), v1, "admin", RepositoryVersionState.UPGRADING);
-    c2.transitionClusterVersion(stackId.getStackId(), v1, RepositoryVersionState.CURRENT);
+    c1.setCurrentStackVersion(stackId);
+    c1.createClusterVersion(stackId.getStackId(), v1, "admin", RepositoryVersionState.UPGRADING);
+    c1.transitionClusterVersion(stackId.getStackId(), v1, RepositoryVersionState.CURRENT);
 
-    clusters.mapHostToCluster("h-1", "c2");
-    clusters.mapHostToCluster("h-2", "c2");
+    clusters.mapHostToCluster("h-1", clusterName);
+    clusters.mapHostToCluster("h-2", clusterName);
 
     ClusterVersionDAOMock.failOnCurrentVersionState = false;
 
-    Service service = c2.addService("ZOOKEEPER");
+    Service service = c1.addService("ZOOKEEPER");
     ServiceComponent sc = service.addServiceComponent("ZOOKEEPER_SERVER");
     sc.addServiceComponentHost("h-1");
     sc.addServiceComponentHost("h-2");
 
-    c2.createClusterVersion(stackId.getStackId(), v2, "admin", RepositoryVersionState.INSTALLING);
-    c2.transitionClusterVersion(stackId.getStackId(), v2, RepositoryVersionState.INSTALLED);
-    c2.transitionClusterVersion(stackId.getStackId(), v2, RepositoryVersionState.OUT_OF_SYNC);
+    c1.createClusterVersion(stackId.getStackId(), v2, "admin", RepositoryVersionState.INSTALLING);
+    c1.transitionClusterVersion(stackId.getStackId(), v2, RepositoryVersionState.INSTALLED);
+    c1.transitionClusterVersion(stackId.getStackId(), v2, RepositoryVersionState.OUT_OF_SYNC);
 
-    clusters.mapHostToCluster(h3, "c2");
+    clusters.mapHostToCluster(h3, clusterName);
 
     // This method is usually called when we receive heartbeat from new host
     HostEntity hostEntity3 = mock(HostEntity.class);
@@ -1305,15 +1739,15 @@ public class ClusterTest {
     HostVersionDAO hostVersionDAOMock = mock(HostVersionDAO.class);
     Field field = ClusterImpl.class.getDeclaredField("hostVersionDAO");
     field.setAccessible(true);
-    field.set(c2, hostVersionDAOMock);
+    field.set(c1, hostVersionDAOMock);
 
     ArgumentCaptor<HostVersionEntity> hostVersionCaptor = ArgumentCaptor.forClass(HostVersionEntity.class);
 
     ClusterVersionDAOMock.mockedClusterVersions = new ArrayList<ClusterVersionEntity>() {{
-      addAll(c2.getAllClusterVersions());
+      addAll(c1.getAllClusterVersions());
     }};
 
-    c2.transitionHostVersionState(hostEntity3, rve1, stackId);
+    c1.transitionHostVersionState(hostEntity3, rve1, stackId);
 
     // Revert fields of static instance
     ClusterVersionDAOMock.mockedClusterVersions = null;
@@ -1321,5 +1755,4 @@ public class ClusterTest {
     verify(hostVersionDAOMock).merge(hostVersionCaptor.capture());
     assertEquals(hostVersionCaptor.getValue().getState(), RepositoryVersionState.CURRENT);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/GANGLIA/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/GANGLIA/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/GANGLIA/metainfo.xml
index fe5f482..9167f87 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/GANGLIA/metainfo.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/GANGLIA/metainfo.xml
@@ -27,6 +27,7 @@
           <name>GANGLIA_SERVER</name>
           <category>MASTER</category>
           <cardinality>1</cardinality>
+          <versionAdvertised>false</versionAdvertised>
           <commandScript>
             <script>scripts/ganglia_server.py</script>
             <scriptType>PYTHON</scriptType>
@@ -38,6 +39,7 @@
           <name>GANGLIA_MONITOR</name>
           <category>SLAVE</category>
           <cardinality>ALL</cardinality>
+          <versionAdvertised>false</versionAdvertised>
           <auto-deploy>
             <enabled>true</enabled>
           </auto-deploy>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml
index e0a40b0..b5e6bc2 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml
@@ -28,6 +28,7 @@
           <name>NAMENODE</name>
           <category>MASTER</category>
           <cardinality>1</cardinality>
+          <versionAdvertised>true</versionAdvertised>
           <commandScript>
             <script>scripts/namenode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -58,6 +59,7 @@
           <name>DATANODE</name>
           <category>SLAVE</category>
           <cardinality>1+</cardinality>
+          <versionAdvertised>true</versionAdvertised>
           <commandScript>
             <script>scripts/datanode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -68,6 +70,7 @@
         <component>
           <name>SECONDARY_NAMENODE</name>
           <!-- TODO:  cardinality is conditional on HA usage -->
+          <versionAdvertised>false</versionAdvertised>
           <cardinality>1</cardinality>
           <category>MASTER</category>
           <commandScript>
@@ -81,6 +84,7 @@
           <name>HDFS_CLIENT</name>
           <category>CLIENT</category>
           <cardinality>0+</cardinality>
+          <versionAdvertised>true</versionAdvertised>
           <commandScript>
             <script>scripts/hdfs_client.py</script>
             <scriptType>PYTHON</scriptType>
@@ -92,6 +96,7 @@
           <name>JOURNALNODE</name>
           <category>SLAVE</category>
           <cardinality>0+</cardinality>
+          <versionAdvertised>true</versionAdvertised>
           <commandScript>
             <script>scripts/journalnode.py</script>
             <scriptType>PYTHON</scriptType>
@@ -103,6 +108,7 @@
           <name>ZKFC</name>
           <category>SLAVE</category>
           <!-- TODO: cardinality is conditional on HA topology -->
+          <versionAdvertised>false</versionAdvertised>
           <cardinality>0+</cardinality>
           <commandScript>
             <script>scripts/zkfc_slave.py</script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/ZOOKEEPER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/ZOOKEEPER/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/ZOOKEEPER/metainfo.xml
index 205b445..1c988f7 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/ZOOKEEPER/metainfo.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/ZOOKEEPER/metainfo.xml
@@ -41,6 +41,7 @@
           <name>ZOOKEEPER_CLIENT</name>
           <category>CLIENT</category>
           <cardinality>0+</cardinality>
+          <versionAdvertised>true</versionAdvertised>
           <commandScript>
             <script>scripts/zookeeper_client.py</script>
             <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/metainfo.xml
new file mode 100644
index 0000000..0fb46fe
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/metainfo.xml
@@ -0,0 +1,24 @@
+<?xml version="1.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.
+-->
+<metainfo>
+    <versions>
+      <active>true</active>
+    </versions>
+    <extends>2.1.1</extends>
+</metainfo>
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
new file mode 100644
index 0000000..37a6a60
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
@@ -0,0 +1,10 @@
+{
+  "HDP-2.2.0": {
+    "latest": {
+      "centos6": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.2.0.0-123",
+      "redhat6": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.2.2.0-123",
+      "oraclelinux6": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.2.0.0-123",
+      "suse11": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/suse11/2.x/BUILDS/2.2.0.0-123/hdp.repo"
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f5c7ac41/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/repoinfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/repoinfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/repoinfo.xml
new file mode 100644
index 0000000..2a939f1
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/repoinfo.xml
@@ -0,0 +1,62 @@
+<?xml version="1.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.
+-->
+<reposinfo>
+  <latest>./hdp.json</latest>
+  <os family="centos6">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+  <os family="centos5">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+  <os family="redhat6">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+  <os family="redhat5">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+  <os family="suse11">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/suse11/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+  <os family="sles11">
+    <repo>
+      <baseurl>http://public-repo-1.hortonworks.com/HDP/suse11/2.x/updates/2.2.0.0</baseurl>
+      <repoid>HDP-2.2.0</repoid>
+      <reponame>HDP</reponame>
+    </repo>
+  </os>
+</reposinfo>