/*
* 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 static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.File;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.OsDetails;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
import org.apache.brooklyn.core.test.entity.TestApplication;
import org.apache.brooklyn.util.core.ResourceUtils;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.commons.io.FileUtils;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.google.common.net.HostAndPort;
public class RebindJcloudsLocationLiveTest extends AbstractJcloudsLiveTest {
public static final String AWS_EC2_REGION_NAME = AWS_EC2_USEAST_REGION_NAME;
public static final String AWS_EC2_LOCATION_SPEC = "jclouds:" + AWS_EC2_PROVIDER + ":" + AWS_EC2_REGION_NAME;
private ClassLoader classLoader = getClass().getClassLoader();
private File mementoDir;
private TestApplication origApp;
@BeforeMethod(alwaysRun=true)
@Override
public void setUp() throws Exception {
super.setUp();
jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
jcloudsLocation.config().set(JcloudsLocation.HARDWARE_ID, AWS_EC2_SMALL_HARDWARE_ID);
origApp = TestApplication.Factory.newManagedInstanceForTests(managementContext);
}
@AfterMethod(alwaysRun = true)
@Override
public void tearDown() throws Exception {
try {
super.tearDown();
} finally {
if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
}
}
@Override
protected LocalManagementContext newManagementContext() {
mementoDir = Files.createTempDir();
return RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader, 1);
}
@Test(groups="Live")
public void testRebindsToJcloudsMachine() throws Exception {
LiveTestEntity origEntity = origApp.addChild(EntitySpec.create(LiveTestEntity.class));
origApp.start(ImmutableList.of(jcloudsLocation));
JcloudsLocation origJcloudsLocation = jcloudsLocation;
System.out.println("orig locations: " + origEntity.getLocations());
JcloudsSshMachineLocation origMachine = (JcloudsSshMachineLocation) Iterables.find(origEntity.getLocations(), Predicates.instanceOf(JcloudsSshMachineLocation.class));
TestApplication newApp = rebind();
LiveTestEntity newEntity = (LiveTestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(LiveTestEntity.class));
JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) Iterables.find(newEntity.getLocations(), Predicates.instanceOf(JcloudsSshMachineLocation.class));
assertMachineEquals(newMachine, origMachine, true); // Don't expect OsDetails, because that is not persisted.
assertTrue(newMachine.isSshable());
JcloudsLocation newJcloudsLoction = newMachine.getParent();
assertJcloudsLocationEquals(newJcloudsLoction, origJcloudsLocation);
}
// TODO In jclouds-azure, the AzureComputeTemplateOptions fields changed, which meant old
// persisted state could not be deserialized. These files are examples of the old format.
@Test(groups={"Live", "WIP"}, enabled=false)
public void testRebindsToJcloudsMachineWithInvalidTemplate() throws Exception {
ResourceUtils resourceUtils = ResourceUtils.create(this);
FileUtils.write(
new File(mementoDir, "locations/briByOel"),
resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-azure-parent-briByOel"));
FileUtils.write(
new File(mementoDir, "locations/VNapYjwp"),
resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-azure-machine-VNapYjwp"));
TestApplication newApp = rebind();
JcloudsLocation loc = (JcloudsLocation) newApp.getManagementContext().getLocationManager().getLocation("briByOel");
JcloudsSshMachineLocation machine = (JcloudsSshMachineLocation) newApp.getManagementContext().getLocationManager().getLocation("VNapYjwp");
assertEquals(ImmutableSet.of(loc.getChildren()), ImmutableSet.of(machine));
}
@Test(groups={"Live", "Live-sanity"})
public void testRebindsToJcloudsSshMachineWithTemplateAndNode() throws Exception {
// Populate the mementoDir with some old-style peristed state
ResourceUtils resourceUtils = ResourceUtils.create(this);
String origParentXml = resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-aws-parent-lCYB3mTb");
String origMachineXml = resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-aws-machine-aKEcbxKN");
File persistedParentFile = new File(mementoDir, "locations/lCYB3mTb");
File persistedMachineFile = new File(mementoDir, "locations/aKEcbxKN");
FileUtils.write(
persistedParentFile,
origParentXml);
FileUtils.write(
persistedMachineFile,
origMachineXml);
assertTrue(origMachineXml.contains("AWSEC2TemplateOptions"), origMachineXml);
assertTrue(origMachineXml.contains("NodeMetadataImpl"), origMachineXml);
// Rebind to the old-style persisted state, which includes the NodeMetadata and the Template objects.
// Expect to parse that ok.
TestApplication app2 = rebind();
JcloudsLocation loc2 = (JcloudsLocation) app2.getManagementContext().getLocationManager().getLocation("lCYB3mTb");
JcloudsSshMachineLocation machine2 = (JcloudsSshMachineLocation) app2.getManagementContext().getLocationManager().getLocation("aKEcbxKN");
assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
String errmsg = "loc="+loc2.toVerboseString()+"; machine="+machine2.toVerboseString();
assertEquals(machine2.getId(), "aKEcbxKN", errmsg);
assertEquals(machine2.getJcloudsId(), "ap-southeast-1/i-56fd53f2", errmsg);
assertEquals(machine2.getSshHostAndPort(), HostAndPort.fromParts("ec2-54-254-23-53.ap-southeast-1.compute.amazonaws.com", 22), errmsg);
assertEquals(machine2.getPrivateAddresses(), ImmutableSet.of("10.144.66.5"), errmsg);
assertEquals(machine2.getPublicAddresses(), ImmutableSet.of("54.254.23.53"), errmsg);
assertEquals(machine2.getPrivateAddress(), Optional.of("10.144.66.5"), errmsg);
assertEquals(machine2.getHostname(), "ip-10-144-66-5", errmsg); // TODO would prefer the hostname that works inside and out
assertEquals(machine2.getOsDetails().isWindows(), false, errmsg);
assertEquals(machine2.getOsDetails().isLinux(), true, errmsg);
assertEquals(machine2.getOsDetails().isMac(), false, errmsg);
assertEquals(machine2.getOsDetails().getName(), "centos", errmsg);
assertEquals(machine2.getOsDetails().getArch(), "x86_64", errmsg);
assertEquals(machine2.getOsDetails().getVersion(), "6.5", errmsg);
assertEquals(machine2.getOsDetails().is64bit(), true, errmsg);
// Force it to be persisted again. Expect to pesist without the NodeMetadata and Template.
app2.getManagementContext().getRebindManager().getChangeListener().onChanged(loc2);
app2.getManagementContext().getRebindManager().getChangeListener().onChanged(machine2);
RebindTestUtils.waitForPersisted(app2);
String newMachineXml = new String(java.nio.file.Files.readAllBytes(persistedMachineFile.toPath()));
assertFalse(newMachineXml.contains("AWSEC2TemplateOptions"), newMachineXml);
assertFalse(newMachineXml.contains("NodeMetadataImpl"), newMachineXml);
// Rebind again, with the re-written persisted state.
TestApplication app3 = rebind();
JcloudsLocation loc3 = (JcloudsLocation) app3.getManagementContext().getLocationManager().getLocation("lCYB3mTb");
JcloudsSshMachineLocation machine3 = (JcloudsSshMachineLocation) app3.getManagementContext().getLocationManager().getLocation("aKEcbxKN");
assertEquals(ImmutableSet.copyOf(loc3.getChildren()), ImmutableSet.of(machine3));
errmsg = "loc="+loc3.toVerboseString()+"; machine="+machine3.toVerboseString();
assertEquals(machine3.getId(), "aKEcbxKN", errmsg);
assertEquals(machine3.getJcloudsId(), "ap-southeast-1/i-56fd53f2", errmsg);
assertEquals(machine3.getSshHostAndPort(), HostAndPort.fromParts("ec2-54-254-23-53.ap-southeast-1.compute.amazonaws.com", 22), errmsg);
assertEquals(machine3.getPrivateAddresses(), ImmutableSet.of("10.144.66.5"), errmsg);
assertEquals(machine3.getPublicAddresses(), ImmutableSet.of("54.254.23.53"), errmsg);
assertEquals(machine3.getPrivateAddress(), Optional.of("10.144.66.5"), errmsg);
assertEquals(machine3.getHostname(), "ip-10-144-66-5", errmsg); // TODO would prefer the hostname that works inside and out
// The VM is no longer running, so won't be able to infer OS Details.
assertFalse(machine3.getOptionalOsDetails().isPresent(), errmsg);
}
@Test(groups={"Live", "Live-sanity"})
public void testRebindsToJcloudsWinrmMachineWithTemplateAndNode() throws Exception {
// Populate the mementoDir with some old-style peristed state
ResourceUtils resourceUtils = ResourceUtils.create(this);
String origParentXml = resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-aws-winrm-parent-fKc0Ofyn");
String origMachineXml = resourceUtils.getResourceAsString("classpath://org/apache/brooklyn/location/jclouds/persisted-aws-winrm-machine-KYSryzW8");
File persistedParentFile = new File(mementoDir, "locations/fKc0Ofyn");
File persistedMachineFile = new File(mementoDir, "locations/KYSryzW8");
FileUtils.write(
persistedParentFile,
origParentXml);
FileUtils.write(
persistedMachineFile,
origMachineXml);
assertTrue(origMachineXml.contains("NodeMetadataImpl"), origMachineXml);
// Rebind to the old-style persisted state, which includes the NodeMetadata and the Template objects.
// Expect to parse that ok.
TestApplication app2 = rebind();
JcloudsLocation loc2 = (JcloudsLocation) app2.getManagementContext().getLocationManager().getLocation("fKc0Ofyn");
JcloudsWinRmMachineLocation machine2 = (JcloudsWinRmMachineLocation) app2.getManagementContext().getLocationManager().getLocation("KYSryzW8");
assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
String errmsg = "loc="+loc2.toVerboseString()+"; machine="+machine2.toVerboseString();
assertEquals(machine2.getId(), "KYSryzW8", errmsg);
assertEquals(machine2.getJcloudsId(), "eu-central-1/i-372eda8a", errmsg);
assertEquals(machine2.getAddress().getHostAddress(), "52.28.153.46", errmsg);
assertEquals(machine2.getPort(), 5985, errmsg);
// FIXME assertEquals(machine2.getAddress().getHostAddress(), HostAndPort.fromParts("ec2-52-28-153-46.eu-central-1.compute.amazonaws.com", 22), errmsg);
assertEquals(machine2.getPrivateAddresses(), ImmutableSet.of("172.31.18.175"), errmsg);
assertEquals(machine2.getPublicAddresses(), ImmutableSet.of("52.28.153.46"), errmsg);
assertEquals(machine2.getPrivateAddress(), Optional.of("172.31.18.175"), errmsg);
assertEquals(machine2.getHostname(), "ip-172-31-18-175", errmsg); // TODO would prefer the hostname that works inside and out
assertNull(machine2.getOsDetails(), errmsg); // JcloudsWinRmMachineLocation never had OsDetails
// Force it to be persisted again. Expect to pesist without the NodeMetadata and Template.
app2.getManagementContext().getRebindManager().getChangeListener().onChanged(loc2);
app2.getManagementContext().getRebindManager().getChangeListener().onChanged(machine2);
RebindTestUtils.waitForPersisted(app2);
String newMachineXml = new String(java.nio.file.Files.readAllBytes(persistedMachineFile.toPath()));
assertFalse(newMachineXml.contains("NodeMetadataImpl"), newMachineXml);
// Rebind again, with the re-written persisted state.
TestApplication app3 = rebind();
JcloudsLocation loc3 = (JcloudsLocation) app3.getManagementContext().getLocationManager().getLocation("fKc0Ofyn");
JcloudsWinRmMachineLocation machine3 = (JcloudsWinRmMachineLocation) app3.getManagementContext().getLocationManager().getLocation("KYSryzW8");
assertEquals(ImmutableSet.copyOf(loc3.getChildren()), ImmutableSet.of(machine3));
errmsg = "loc="+loc3.toVerboseString()+"; machine="+machine3.toVerboseString();
assertEquals(machine3.getId(), "KYSryzW8", errmsg);
assertEquals(machine3.getJcloudsId(), "eu-central-1/i-372eda8a", errmsg);
assertEquals(machine3.getAddress().getHostAddress(), "52.28.153.46", errmsg);
assertEquals(machine3.getPort(), 5985, errmsg);
assertEquals(machine3.getPrivateAddresses(), ImmutableSet.of("172.31.18.175"), errmsg);
assertEquals(machine3.getPublicAddresses(), ImmutableSet.of("52.28.153.46"), errmsg);
assertEquals(machine3.getPrivateAddress(), Optional.of("172.31.18.175"), errmsg);
assertEquals(machine3.getHostname(), "ip-172-31-18-175", errmsg); // TODO would prefer the hostname that works inside and out
assertNull(machine2.getOsDetails(), errmsg); // JcloudsWinRmMachineLocation never had OsDetails
}
private void assertMachineEquals(JcloudsSshMachineLocation actual, JcloudsSshMachineLocation expected, boolean expectNoOsDetails) {
String errmsg = "actual="+actual.toVerboseString()+"; expected="+expected.toVerboseString();
assertEquals(actual.getId(), expected.getId(), errmsg);
assertEquals(actual.getJcloudsId(), expected.getJcloudsId(), errmsg);
if (expectNoOsDetails) {
assertOsDetailEquals(actual.getOptionalOsDetails(), Optional.<OsDetails>absent());
} else {
assertOsDetailEquals(actual.getOptionalOsDetails(), expected.getOptionalOsDetails());
}
assertEquals(actual.getSshHostAndPort(), expected.getSshHostAndPort());
assertEquals(actual.getPrivateAddress(), expected.getPrivateAddress());
assertConfigBagEquals(actual.config().getBag(), expected.config().getBag(), errmsg);
}
private void assertOsDetailEquals(Optional<OsDetails> actual, Optional<OsDetails> expected) {
String errmsg = "actual="+actual+"; expected="+expected;
if (actual.isPresent()) {
assertEquals(actual.get().isWindows(), expected.get().isWindows());
assertEquals(actual.get().isLinux(), expected.get().isLinux());
assertEquals(actual.get().isMac(), expected.get().isMac());
assertEquals(actual.get().getName(), expected.get().getName());
assertEquals(actual.get().getArch(), expected.get().getArch());
assertEquals(actual.get().getVersion(), expected.get().getVersion());
assertEquals(actual.get().is64bit(), expected.get().is64bit());
} else {
assertFalse(expected.isPresent(), errmsg);
}
}
private void assertJcloudsLocationEquals(JcloudsLocation actual, JcloudsLocation expected) {
String errmsg = "actual="+actual.toVerboseString()+"; expected="+expected.toVerboseString();
assertEquals(actual.getId(), expected.getId(), errmsg);
assertEquals(actual.getProvider(), expected.getProvider(), errmsg);
assertEquals(actual.getRegion(), expected.getRegion(), errmsg);
assertEquals(actual.getIdentity(), expected.getIdentity(), errmsg);
assertEquals(actual.getCredential(), expected.getCredential(), errmsg);
assertEquals(actual.getHostGeoInfo(), expected.getHostGeoInfo(), errmsg);
assertConfigBagEquals(actual.config().getBag(), expected.config().getBag(), errmsg);
}
private void assertConfigBagEquals(ConfigBag actual, ConfigBag expected, String errmsg) {
// TODO revisit the strong assertion that configBags are equal
// // TODO Can we include all of these things (e.g. when locations are entities, so flagged fields not treated special)?
// List<String> configToIgnore = ImmutableList.of("id", "template", "usedPorts", "machineCreationSemaphore", "config");
// MutableMap<Object, Object> actualMap = MutableMap.builder().putAll(actual.getAllConfig())
// .removeAll(configToIgnore)
// .build();
// MutableMap<Object, Object> expectedMap = MutableMap.builder().putAll(expected.getAllConfig())
// .removeAll(configToIgnore)
// .build();
//
// assertEquals(actualMap, expectedMap, errmsg+"; actualBag="+actualMap+"; expectedBag="+expectedMap);
}
private TestApplication rebind() throws Exception {
return rebind(RebindOptions.create()
.mementoDir(mementoDir)
.classLoader(classLoader));
}
private TestApplication rebind(RebindOptions options) throws Exception {
RebindTestUtils.waitForPersisted(origApp);
return (TestApplication) RebindTestUtils.rebind(options);
}
}