Repository: incubator-brooklyn Updated Branches: refs/heads/master 94687d98a -> 206d78256
Adds jclouds rebind tests Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/eb7d1208 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/eb7d1208 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/eb7d1208 Branch: refs/heads/master Commit: eb7d1208b4b3d0453ac33c388f949d02b09ba7a1 Parents: fa131b1 Author: Aled Sage <[email protected]> Authored: Thu Oct 8 20:33:29 2015 +0100 Committer: Aled Sage <[email protected]> Committed: Thu Oct 8 20:33:29 2015 +0100 ---------------------------------------------------------------------- .../core/mgmt/rebind/RebindTestFixture.java | 4 + .../jclouds/AbstractJcloudsLiveTest.java | 25 +- .../jclouds/JcloudsByonRebindLiveTest.java | 165 ++++++++++++ .../location/jclouds/JcloudsRebindLiveTest.java | 188 ++++++++++++++ .../location/jclouds/JcloudsRebindStubTest.java | 250 +++++++++++++++++++ 5 files changed, 623 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb7d1208/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java index df2e658..c9acdf3 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java @@ -124,6 +124,10 @@ public abstract class RebindTestFixture<T extends StartableApplication> { newApp = null; } + protected ManagementContext mgmt() { + return (newManagementContext != null) ? newManagementContext : origManagementContext; + } + public static void waitForTaskCountToBecome(final ManagementContext mgmt, final int allowedMax) { waitForTaskCountToBecome(mgmt, allowedMax, false); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb7d1208/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java index 13138a5..3a475c0 100644 --- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java @@ -81,14 +81,7 @@ public class AbstractJcloudsLiveTest { List<Exception> exceptions = Lists.newArrayList(); try { if (machines != null) { - for (JcloudsSshMachineLocation machine : machines) { - try { - releaseMachine(machine); - } catch (Exception e) { - LOG.warn("Error releasing machine "+machine+"; continuing...", e); - exceptions.add(e); - } - } + exceptions.addAll(releaseMachineSafely(machines)); machines.clear(); } } finally { @@ -115,7 +108,7 @@ public class AbstractJcloudsLiveTest { return LocalManagementContextForTests.builder(true).useDefaultProperties().build(); } - protected void stripBrooklynProperties(BrooklynProperties props) { + protected static void stripBrooklynProperties(BrooklynProperties props) { // remove all location properties except for identity and credential // (so key, scripts, etc settings don't interfere with tests) for (String key : ImmutableSet.copyOf(props.asMapWithStringKeys().keySet())) { @@ -155,6 +148,20 @@ public class AbstractJcloudsLiveTest { machines.remove(machine); jcloudsLocation.release(machine); } + + protected List<Exception> releaseMachineSafely(Iterable<? extends JcloudsSshMachineLocation> machines) { + List<Exception> exceptions = Lists.newArrayList(); + + for (JcloudsSshMachineLocation machine : machines) { + try { + releaseMachine(machine); + } catch (Exception e) { + LOG.warn("Error releasing machine "+machine+"; continuing...", e); + exceptions.add(e); + } + } + return exceptions; + } protected void suspendMachine(MachineLocation machine) { assertNotNull(jcloudsLocation); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb7d1208/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonRebindLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonRebindLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonRebindLiveTest.java new file mode 100644 index 0000000..705935b --- /dev/null +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonRebindLiveTest.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.location.jclouds; + +import static org.testng.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; +import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp; +import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; +import org.apache.brooklyn.location.byon.FixedListMachineProvisioningLocation; +import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; +import org.apache.brooklyn.util.stream.Streams; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + +/** + * Tests rebind (i.e. restarting Brooklyn server) when there are live JcloudsSshMachineLocation object(s), + * created using the JcloudsByonLocationResolver. + */ +public class JcloudsByonRebindLiveTest extends RebindTestFixtureWithApp { + + // TODO Duplication of AbstractJcloudsLiveTest, because we're subclassing RebindTestFixture instead. + + private static final Logger LOG = LoggerFactory.getLogger(JcloudsByonRebindLiveTest.class); + + public static final String SOFTLAYER_PROVIDER = AbstractJcloudsLiveTest.SOFTLAYER_PROVIDER; + public static final String SOFTLAYER_REGION = AbstractJcloudsLiveTest.SOFTLAYER_AMS01_REGION_NAME; + public static final String SOFTLAYER_LOCATION_SPEC = "jclouds:" + SOFTLAYER_PROVIDER + ":" + SOFTLAYER_REGION; + public static final String SOFTLAYER_IMAGE_ID = "UBUNTU_14_64"; + + private LocalManagementContext provisioningManagementContext; + private JcloudsSshMachineLocation provisionedMachine; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + + // For provisioning VMs (to subsequently be used for BYON) + provisioningManagementContext = LocalManagementContextForTests.builder(true).useDefaultProperties().build(); + AbstractJcloudsLiveTest.stripBrooklynProperties(provisioningManagementContext.getBrooklynProperties()); + + // Don't let any defaults from brooklyn.properties (except credentials) interfere with test + AbstractJcloudsLiveTest.stripBrooklynProperties(origManagementContext.getBrooklynProperties()); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + List<Exception> exceptions = Lists.newArrayList(); + try { + if (provisioningManagementContext != null && provisionedMachine != null) { + provisionedMachine.getParent().release(provisionedMachine); + } + } finally { + Entities.destroyAll(provisioningManagementContext); + provisioningManagementContext = null; + provisionedMachine = null; + + super.tearDown(); + } + + if (exceptions.size() > 0) { + throw new CompoundRuntimeException("Error in tearDown of "+getClass(), exceptions); + } + } + + @Override + protected boolean useLiveManagementContext() { + return true; + } + + @Test(groups = {"Live"}) + public void testRebind() throws Exception { + ImmutableMap<String, Object> obtainFlags = ImmutableMap.<String,Object>builder() + .put("imageId", SOFTLAYER_IMAGE_ID) + .put("inboundPorts", ImmutableList.of(22)) + .build(); + JcloudsLocation provisioningLoc = (JcloudsLocation) provisioningManagementContext.getLocationRegistry().resolve(SOFTLAYER_LOCATION_SPEC); + provisionedMachine = (JcloudsSshMachineLocation) provisioningLoc.obtain(obtainFlags); + + // Test with a jclouds-byon + String locSpec = "jcloudsByon:(provider=\""+SOFTLAYER_PROVIDER+"\",region=\""+SOFTLAYER_REGION+"\",user=\""+provisionedMachine.getUser()+"\",hosts=\""+provisionedMachine.getNode().getProviderId()+"\")"; + + FixedListMachineProvisioningLocation<?> origByon = (FixedListMachineProvisioningLocation<?>) mgmt().getLocationRegistry().resolve(locSpec); + + JcloudsSshMachineLocation origMachine = (JcloudsSshMachineLocation)origByon.obtain(ImmutableMap.<String,Object>of()); + JcloudsLocation origJcloudsLocation = origMachine.getParent(); + String origHostname = origMachine.getHostname(); + NodeMetadata origNode = origMachine.getNode(); + Template origTemplate = origMachine.getTemplate(); + assertSshable(origMachine); + + rebind(); + + // Check the machine is as before + JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) newManagementContext.getLocationManager().getLocation(origMachine.getId()); + FixedListMachineProvisioningLocation<?> newByon = (FixedListMachineProvisioningLocation<?>) newManagementContext.getLocationManager().getLocation(origByon.getId()); + JcloudsLocation newJcloudsLocation = newMachine.getParent(); + String newHostname = newMachine.getHostname(); + NodeMetadata newNode = newMachine.getNode(); + Template newTemplate = newMachine.getTemplate(); + assertSshable(newMachine); + + assertEquals(newHostname, origHostname); + assertEquals(origNode.getId(), newNode.getId()); + + assertEquals(newJcloudsLocation.getProvider(), origJcloudsLocation.getProvider()); + } + + protected void assertSshable(Map<?,?> machineConfig) { + SshMachineLocation machineWithThatConfig = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) + .configure(machineConfig)); + try { + assertSshable(machineWithThatConfig); + } finally { + Streams.closeQuietly(machineWithThatConfig); + } + } + + protected void assertNotSshable(Map<?,?> machineConfig) { + try { + assertSshable(machineConfig); + Assert.fail("ssh should not have succeeded "+machineConfig); + } catch (Exception e) { + // expected + LOG.debug("Exception as expected when testing sshable "+machineConfig); + } + } + + protected void assertSshable(SshMachineLocation machine) { + int result = machine.execScript("simplecommand", ImmutableList.of("true")); + assertEquals(result, 0); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb7d1208/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindLiveTest.java new file mode 100644 index 0000000..b81d930 --- /dev/null +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindLiveTest.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.location.jclouds; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.api.location.MachineProvisioningLocation; +import org.apache.brooklyn.core.location.Locations; +import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp; +import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; +import org.apache.brooklyn.util.stream.Streams; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + +/** + * Tests rebind (i.e. restarting Brooklyn server) when there are live JcloudsSshMachineLocation object(s). + */ +public class JcloudsRebindLiveTest extends RebindTestFixtureWithApp { + + // TODO Duplication of AbstractJcloudsLiveTest, because we're subcalling RebindTestFixture instead. + + // TODO The mgmts tracking was added when I tried to combine JcloudsRebindLiveTest and JcloudsByonRebindLiveTest, + // but turns out that is not worth the effort! + + private static final Logger LOG = LoggerFactory.getLogger(JcloudsRebindLiveTest.class); + + public static final String AWS_EC2_REGION_NAME = AbstractJcloudsLiveTest.AWS_EC2_USEAST_REGION_NAME; + public static final String AWS_EC2_LOCATION_SPEC = "jclouds:" + AbstractJcloudsLiveTest.AWS_EC2_PROVIDER + (AWS_EC2_REGION_NAME == null ? "" : ":" + AWS_EC2_REGION_NAME); + + // Image: {id=us-east-1/ami-7d7bfc14, providerId=ami-7d7bfc14, name=RightImage_CentOS_6.3_x64_v5.8.8.5, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=centos, arch=paravirtual, version=6.0, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, is64Bit=true}, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, version=5.8.8.5, status=AVAILABLE[available], loginUser=root, userMetadata={owner=411009282317, rootDeviceType=instance-store, virtualizationType=paravirtual, hypervisor=xen}} + public static final String AWS_EC2_CENTOS_IMAGE_ID = "us-east-1/ami-7d7bfc14"; + + public static final String SOFTLAYER_LOCATION_SPEC = "jclouds:" + AbstractJcloudsLiveTest.SOFTLAYER_PROVIDER; + + protected List<JcloudsSshMachineLocation> machines; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + machines = Lists.newCopyOnWriteArrayList(); + + // Don't let any defaults from brooklyn.properties (except credentials) interfere with test + AbstractJcloudsLiveTest.stripBrooklynProperties(origManagementContext.getBrooklynProperties()); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + List<Exception> exceptions = Lists.newArrayList(); + try { + exceptions.addAll(releaseMachineSafely(machines)); + machines.clear(); + } finally { + super.tearDown(); + } + + if (exceptions.size() > 0) { + throw new CompoundRuntimeException("Error in tearDown of "+getClass(), exceptions); + } + } + + @Override + protected boolean useLiveManagementContext() { + return true; + } + + @Test(groups = {"Live"}) + public void testEc2Rebind() throws Exception { + ImmutableMap<String, Object> obtainFlags = ImmutableMap.<String,Object>builder() + .put("imageId", AWS_EC2_CENTOS_IMAGE_ID) + .put("hardwareId", AbstractJcloudsLiveTest.AWS_EC2_SMALL_HARDWARE_ID) + .put("inboundPorts", ImmutableList.of(22)) + .build(); + runTest(AWS_EC2_LOCATION_SPEC, obtainFlags); + } + + @Test(groups = {"Live"}) + public void testSoftlayerRebind() throws Exception { + runTest(SOFTLAYER_LOCATION_SPEC, ImmutableMap.of("inboundPorts", ImmutableList.of(22))); + } + + protected void runTest(String locSpec, Map<String, ?> obtainFlags) throws Exception { + JcloudsLocation location = (JcloudsLocation) mgmt().getLocationRegistry().resolve(locSpec); + + JcloudsSshMachineLocation origMachine = obtainMachine(location, obtainFlags); + String origHostname = origMachine.getHostname(); + NodeMetadata origNode = origMachine.getNode(); + Template origTemplate = origMachine.getTemplate(); + assertSshable(origMachine); + + rebind(); + + // Check the machine is as before + JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) newManagementContext.getLocationManager().getLocation(origMachine.getId()); + JcloudsLocation newLocation = newMachine.getParent(); + String newHostname = newMachine.getHostname(); + NodeMetadata newNode = newMachine.getNode(); + Template newTemplate = newMachine.getTemplate(); + assertSshable(newMachine); + + assertEquals(newHostname, origHostname); + assertEquals(origNode.getId(), newNode.getId()); + } + + protected void assertSshable(Map<?,?> machineConfig) { + SshMachineLocation machineWithThatConfig = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) + .configure(machineConfig)); + try { + assertSshable(machineWithThatConfig); + } finally { + Streams.closeQuietly(machineWithThatConfig); + } + } + + protected void assertNotSshable(Map<?,?> machineConfig) { + try { + assertSshable(machineConfig); + Assert.fail("ssh should not have succeeded "+machineConfig); + } catch (Exception e) { + // expected + LOG.debug("Exception as expected when testing sshable "+machineConfig); + } + } + + protected void assertSshable(SshMachineLocation machine) { + int result = machine.execScript("simplecommand", ImmutableList.of("true")); + assertEquals(result, 0); + } + + // Use this utility method to ensure machines are released on tearDown + protected JcloudsSshMachineLocation obtainMachine(MachineProvisioningLocation<?> location, Map<?, ?> conf) throws Exception { + JcloudsSshMachineLocation result = (JcloudsSshMachineLocation)location.obtain(conf); + machines.add(checkNotNull(result, "result")); + return result; + } + + protected void releaseMachine(JcloudsSshMachineLocation machine) { + if (!Locations.isManaged(machine)) return; + machines.remove(machine); + machine.getParent().release(machine); + } + + protected List<Exception> releaseMachineSafely(Iterable<? extends JcloudsSshMachineLocation> machines) { + List<Exception> exceptions = Lists.newArrayList(); + List<JcloudsSshMachineLocation> machinesCopy = ImmutableList.copyOf(machines); + + for (JcloudsSshMachineLocation machine : machinesCopy) { + try { + releaseMachine(machine); + } catch (Exception e) { + LOG.warn("Error releasing machine "+machine+"; continuing...", e); + exceptions.add(e); + } + } + return exceptions; + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb7d1208/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubTest.java new file mode 100644 index 0000000..ac7fd56 --- /dev/null +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubTest.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.location.jclouds; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertEquals; + +import java.net.URI; +import java.util.List; +import java.util.Set; + +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.internal.BrooklynProperties; +import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp; +import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadata.Status; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.Processor; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.Volume; +import org.jclouds.compute.domain.internal.HardwareImpl; +import org.jclouds.compute.domain.internal.NodeMetadataImpl; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.domain.LocationScope; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.domain.internal.LocationImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Predicates; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; + +/** + * Tests rebind (i.e. restarting Brooklyn server) when there are live JcloudsSshMachineLocation object(s). + * + * It is still a live test because it connects to the Softlayer API for finding images, etc. + * But it does not provision any VMs, so is much faster/cheaper. + */ +public class JcloudsRebindStubTest extends RebindTestFixtureWithApp { + + // TODO Duplication of AbstractJcloudsLiveTest, because we're subclassing RebindTestFixture instead. + + private static final Logger LOG = LoggerFactory.getLogger(JcloudsRebindStubTest.class); + + public static final String SOFTLAYER_LOCATION_SPEC = "jclouds:" + AbstractJcloudsLiveTest.SOFTLAYER_PROVIDER; + public static final String SOFTLAYER_IMAGE_ID = "UBUNTU_14_64"; + + protected List<ManagementContext> mgmts; + protected Multimap<ManagementContext, JcloudsSshMachineLocation> machines; + protected BrooklynProperties brooklynProperties; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + mgmts = Lists.newCopyOnWriteArrayList(ImmutableList.<ManagementContext>of(origManagementContext)); + machines = Multimaps.synchronizedMultimap(ArrayListMultimap.<ManagementContext, JcloudsSshMachineLocation>create()); + + // Don't let any defaults from brooklyn.properties (except credentials) interfere with test + brooklynProperties = origManagementContext.getBrooklynProperties(); + AbstractJcloudsLiveTest.stripBrooklynProperties(brooklynProperties); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + List<Exception> exceptions = Lists.newArrayList(); + for (ManagementContext mgmt : mgmts) { + try { + if (mgmt.isRunning()) Entities.destroyAll(mgmt); + } catch (Exception e) { + LOG.warn("Error destroying management context", e); + exceptions.add(e); + } + } + mgmts.clear(); + origManagementContext = null; + newManagementContext = null; + origApp = null; + newApp = null; + + super.tearDown(); + + if (exceptions.size() > 0) { + throw new CompoundRuntimeException("Error in tearDown of "+getClass(), exceptions); + } + } + + @Override + protected boolean useLiveManagementContext() { + return true; + } + + @Override + protected TestApplication rebind() throws Exception { + TestApplication result = super.rebind(); + mgmts.add(newManagementContext); + return result; + } + + @Test(groups={"Live", "Live-sanity"}) + public void testRebind() throws Exception { + LocationImpl locImpl = new LocationImpl( + LocationScope.REGION, + "myLocId", + "myLocDescription", + null, + ImmutableList.<String>of(), // iso3166Codes + ImmutableMap.<String,Object>of()); // metadata + + NodeMetadata node = new NodeMetadataImpl( + "softlayer", + "myname", + "myid", + locImpl, + URI.create("http://myuri.com"), + ImmutableMap.<String, String>of(), // userMetadata + ImmutableSet.<String>of(), // tags + "mygroup", + new HardwareImpl( + "myHardwareProviderId", + "myHardwareName", + "myHardwareId", + locImpl, + URI.create("http://myuri.com"), + ImmutableMap.<String, String>of(), // userMetadata + ImmutableSet.<String>of(), // tags + ImmutableList.<Processor>of(), + 1024, + ImmutableList.<Volume>of(), + Predicates.<Image>alwaysTrue(), // supportsImage, + (String)null, // hypervisor + false), + SOFTLAYER_IMAGE_ID, + new OperatingSystem( + OsFamily.CENTOS, + "myOsName", + "myOsVersion", + "myOsArch", + "myDescription", + true), // is64Bit + Status.RUNNING, + "myBackendStatus", + 22, // login-port + ImmutableList.of("1.2.3.4"), // publicAddresses, + ImmutableList.of("10.2.3.4"), // privateAddresses, + LoginCredentials.builder().identity("myidentity").password("mypassword").build(), + "myHostname"); + + ByonComputeServiceRegistry computeServiceRegistry = new ByonComputeServiceRegistry(node); + JcloudsLocation origJcloudsLoc = (JcloudsLocation) mgmt().getLocationRegistry().resolve("jclouds:softlayer", ImmutableMap.of( + JcloudsLocation.COMPUTE_SERVICE_REGISTRY, computeServiceRegistry, + JcloudsLocation.WAIT_FOR_SSHABLE, false, + JcloudsLocation.USE_JCLOUDS_SSH_INIT, false)); + + JcloudsSshMachineLocation origMachine = (JcloudsSshMachineLocation) origJcloudsLoc.obtain(ImmutableMap.of("imageId", SOFTLAYER_IMAGE_ID)); + + String origHostname = origMachine.getHostname(); + NodeMetadata origNode = origMachine.getNode(); + Template origTemplate = origMachine.getTemplate(); + + rebind(); + + // Check the machine is as before + JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) newManagementContext.getLocationManager().getLocation(origMachine.getId()); + JcloudsLocation newJcloudsLoc = newMachine.getParent(); + String newHostname = newMachine.getHostname(); + NodeMetadata newNode = newMachine.getNode(); + Template newTemplate = newMachine.getTemplate(); + + assertEquals(newHostname, origHostname); + assertEquals(origNode.getId(), newNode.getId()); + + assertEquals(newJcloudsLoc.getProvider(), origJcloudsLoc.getProvider()); + } + + protected static class ByonComputeServiceRegistry extends ComputeServiceRegistryImpl implements ComputeServiceRegistry { + private final NodeMetadata node; + + ByonComputeServiceRegistry(NodeMetadata node) throws Exception { + this.node = node; + } + + @Override + public ComputeService findComputeService(ConfigBag conf, boolean allowReuse) { + ComputeService delegate = super.findComputeService(conf, allowReuse); + return new StubComputeService(delegate, node); + } + } + + static class StubComputeService extends DelegatingComputeService { + private final NodeMetadata node; + + public StubComputeService(ComputeService delegate, NodeMetadata node) { + super(delegate); + this.node = checkNotNull(node, "node"); + } + + @Override + public void destroyNode(String id) { + // no-op + } + + @Override + public Set<? extends NodeMetadata> createNodesInGroup(String group, int count) throws RunNodesException { + return ImmutableSet.of(node); + } + + @Override + public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template) throws RunNodesException { + return ImmutableSet.of(node); + } + + @Override + public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, TemplateOptions templateOptions) throws RunNodesException { + return ImmutableSet.of(node); + } + } +}
