Browse Source

AMBARI-9777. Blank current stack version on the host added via addHostWizard (dlysnichenko)

Lisnichenko Dmitro 10 years ago
parent
commit
71bea2aabc

+ 1 - 5
ambari-server/pom.xml

@@ -1428,6 +1428,7 @@
     <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
+      <version>1.4</version>
     </dependency>
     <dependency>
       <groupId>org.apache.commons</groupId>
@@ -1756,11 +1757,6 @@
       <artifactId>snmp4j</artifactId>
       <version>1.10.1</version>
     </dependency>
-	<dependency>
-		<groupId>org.apache.commons</groupId>
-		<artifactId>commons-io</artifactId>
-		<version>1.3.2</version>
-	</dependency>
   </dependencies>
 
   <pluginRepositories>

+ 16 - 9
ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java

@@ -1305,18 +1305,25 @@ public class ClusterImpl implements Cluster {
   @Override
   @Transactional
   public HostVersionEntity transitionHostVersionState(HostEntity host, final RepositoryVersionEntity repositoryVersion, final StackId stack) throws AmbariException {
-    HostVersionEntity hostVersionEntity = null;
     List<HostVersionEntity> hostVersions = hostVersionDAO.findByHost(host.getHostName());
-    if (hostVersions == null || hostVersions.isEmpty()) {
-      // Since the host has no versions, allow bootstrapping a version for it.
+
+    // 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());
+    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);
-    } else {
-      hostVersionEntity = hostVersionDAO.findByClusterStackVersionAndHost(getClusterName(), repositoryVersion.getStack(), repositoryVersion.getVersion(), host.getHostName());
-      if (hostVersionEntity == null) {
-        throw new AmbariException("Host " + host.getHostName() + " is expected to have a Host Version for stack " + repositoryVersion.getStackVersion());
-      }
     }
 
     final ServiceComponentHostSummary hostSummary = new ServiceComponentHostSummary(ambariMetaInfo, host, stack);
@@ -1326,7 +1333,7 @@ public class ClusterImpl implements Cluster {
     // 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) {
+    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.

+ 99 - 0
ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java

@@ -23,8 +23,10 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -100,6 +102,7 @@ import com.google.inject.Singleton;
 import com.google.inject.persist.PersistService;
 import com.google.inject.persist.Transactional;
 import com.google.inject.util.Modules;
+import org.mockito.ArgumentCaptor;
 
 public class ClusterTest {
 
@@ -118,6 +121,7 @@ public class ClusterTest {
   @Singleton
   static class ClusterVersionDAOMock extends ClusterVersionDAO {
     static boolean failOnCurrentVersionState;
+    static List<ClusterVersionEntity> mockedClusterVersions;
 
     @Override
     @Transactional
@@ -128,6 +132,16 @@ public class ClusterTest {
         throw new RollbackException();
       }
     }
+
+    @Override
+    @Transactional
+    public List<ClusterVersionEntity> findByCluster(String clusterName) {
+      if (mockedClusterVersions == null) {
+        return super.findByCluster(clusterName);
+      } else {
+        return mockedClusterVersions;
+      }
+    }
   }
 
   private static class MockModule extends AbstractModule {
@@ -1223,4 +1237,89 @@ public class ClusterTest {
     assertEquals(1, entities.size());
   }
 
+  @Test
+  public void testTransitionHostVersionState_OutOfSync_BlankCurrent() throws Exception {
+    /**
+     * Checks case when there are 2 cluster stack versions present (CURRENT and OUT_OF_SYNC),
+     * 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";
+    clusters.addCluster(clusterName);
+    final Cluster c2 = clusters.getCluster(clusterName);
+    Assert.assertEquals(clusterName, c2.getClusterName());
+    Assert.assertEquals(2, c2.getClusterId());
+
+    clusters.addHost("h-1");
+    clusters.addHost("h-2");
+    String h3 = "h-3";
+    clusters.addHost(h3);
+
+    for (String hostName : new String[] { "h-1", "h-2", h3}) {
+      Host h = clusters.getHost(hostName);
+      h.setIPv4("ipv4");
+      h.setIPv6("ipv6");
+
+      Map<String, String> hostAttributes = new HashMap<String, String>();
+      hostAttributes.put("os_family", "redhat");
+      hostAttributes.put("os_release_version", "5.9");
+      h.setHostAttributes(hostAttributes);
+      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);
+    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);
+
+    clusters.mapHostToCluster("h-1", "c2");
+    clusters.mapHostToCluster("h-2", "c2");
+
+    ClusterVersionDAOMock.failOnCurrentVersionState = false;
+
+    Service service = c2.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);
+
+    clusters.mapHostToCluster(h3, "c2");
+
+    // This method is usually called when we receive heartbeat from new host
+    HostEntity hostEntity3 = mock(HostEntity.class);
+    when(hostEntity3.getHostName()).thenReturn(h3);
+
+    // HACK: to workaround issue with NullPointerException at
+    // org.eclipse.persistence.internal.sessions.MergeManager.registerObjectForMergeCloneIntoWorkingCopy(MergeManager.java:1037)
+    // during hostVersionDAO.merge()
+    HostVersionDAO hostVersionDAOMock = mock(HostVersionDAO.class);
+    Field field = ClusterImpl.class.getDeclaredField("hostVersionDAO");
+    field.setAccessible(true);
+    field.set(c2, hostVersionDAOMock);
+
+    ArgumentCaptor<HostVersionEntity> hostVersionCaptor = ArgumentCaptor.forClass(HostVersionEntity.class);
+
+    ClusterVersionDAOMock.mockedClusterVersions = new ArrayList<ClusterVersionEntity>() {{
+      addAll(c2.getAllClusterVersions());
+    }};
+
+    c2.transitionHostVersionState(hostEntity3, rve1, stackId);
+
+    // Revert fields of static instance
+    ClusterVersionDAOMock.mockedClusterVersions = null;
+
+    verify(hostVersionDAOMock).merge(hostVersionCaptor.capture());
+    assertEquals(hostVersionCaptor.getValue().getState(), RepositoryVersionState.CURRENT);
+  }
+
 }

+ 1 - 1
ambari-views/examples/weather-view/pom.xml

@@ -66,7 +66,7 @@
       <version>1.1</version>
     </dependency>
     <dependency>
-      <groupId>org.apache.commons</groupId>
+      <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
       <version>1.3.2</version>
     </dependency>