/*
* 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.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.location.LocationSpec;
import org.apache.brooklyn.core.location.Locations;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.stream.Streams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Tests that the correct address is advertised for the VM - for its public/private,
* its subnet hostname, etc.
*/
public class JcloudsAddressesLiveTest extends AbstractJcloudsLiveTest {
private static final Logger LOG = LoggerFactory.getLogger(JcloudsAddressesLiveTest.class);
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 == 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";
// Image: {id=us-east-1/ami-d0f89fb9, providerId=ami-d0f89fb9, name=ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=ubuntu, arch=paravirtual, version=12.04, description=099720109477/ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, is64Bit=true}, description=099720109477/ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, version=20130411.1, status=AVAILABLE[available], loginUser=ubuntu, userMetadata={owner=099720109477, rootDeviceType=ebs, virtualizationType=paravirtual, hypervisor=xen}}
public static final String AWS_EC2_UBUNTU_IMAGE_ID = "us-east-1/ami-d0f89fb9";
// Image: {id=us-east-1/ami-5e008437, providerId=ami-5e008437, name=RightImage_Ubuntu_10.04_x64_v5.8.8.3, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=ubuntu, arch=paravirtual, version=10.04, description=rightscale-us-east/RightImage_Ubuntu_10.04_x64_v5.8.8.3.manifest.xml, is64Bit=true}, description=rightscale-us-east/RightImage_Ubuntu_10.04_x64_v5.8.8.3.manifest.xml, version=5.8.8.3, status=AVAILABLE[available], loginUser=root, userMetadata={owner=411009282317, rootDeviceType=instance-store, virtualizationType=paravirtual, hypervisor=xen}}
// Uses "root" as loginUser
public static final String AWS_EC2_UBUNTU_10_IMAGE_ID = "us-east-1/ami-5e008437";
public static final String RACKSPACE_LOCATION_SPEC = "jclouds:" + RACKSPACE_PROVIDER;
// Image: {id=LON/c52a0ca6-c1f2-4cd1-b7d6-afbcd1ebda22, providerId=c52a0ca6-c1f2-4cd1-b7d6-afbcd1ebda22, name=CentOS 6.0, location={scope=ZONE, id=LON, description=LON, parent=rackspace-cloudservers-uk, iso3166Codes=[GB-SLG]}, os={family=centos, name=CentOS 6.0, version=6.0, description=CentOS 6.0, is64Bit=true}, description=CentOS 6.0, status=AVAILABLE, loginUser=root, userMetadata={os_distro=centos, com.rackspace__1__visible_core=1, com.rackspace__1__build_rackconnect=1, com.rackspace__1__options=0, image_type=base, cache_in_nova=True, com.rackspace__1__source=kickstart, org.openstack__1__os_distro=org.centos, com.rackspace__1__release_build_date=2013-07-25_18-56-29, auto_disk_config=True, com.rackspace__1__release_version=5, os_type=linux, com.rackspace__1__visible_rackconnect=1, com.rackspace__1__release_id=210, com.rackspace__1__visible_managed=0, com.rackspace__1__build_core=1, org.openstack__1__os_version=6.0, org.openstack__1__architecture=x64, com.rackspace__1__build_managed=0}}
public static final String RACKSPACE_CENTOS_IMAGE_NAME_REGEX = "CentOS 6.0";
protected JcloudsSshMachineLocation machine;
@Test(groups = {"Live"})
protected void testAwsEc2Addresses() throws Exception {
jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
machine = createEc2Machine(ImmutableMap.<String,Object>of());
assertSshable(machine);
String locationAddress = machine.getAddress().getHostName();
InetAddress address = machine.getAddress();
Set<String> publicAddresses = machine.getPublicAddresses();
Set<String> privateAddresses = machine.getPrivateAddresses();
String subnetIp = machine.getSubnetIp();
String hostname = machine.getHostname();
String subnetHostname = machine.getSubnetHostname();
String msg = "locationAddress="+locationAddress+"; address="+address+"; publicAddrs="+publicAddresses+"; privateAddrs="+privateAddresses+"; subnetIp="+subnetIp+"; hostname="+hostname+"; subnetHostname="+subnetHostname;
LOG.info("node: "+msg);
// On AWS, machine advertises its FQ hostname that is accessible from inside and outside the region
assertReachable(machine, locationAddress, msg);
assertReachableFromMachine(machine, locationAddress, msg);
assertReachable(machine, address, msg);
assertTrue(publicAddresses.size() > 0, msg);
for (String publicAddress: publicAddresses) {
assertReachable(machine, publicAddress, msg);
}
// On AWS, private address is not reachable from outside.
// If you ran this test from the same AWS region, it would fail!
assertTrue(privateAddresses.size() > 0, msg);
for (String privateAddress: privateAddresses) {
assertReachableFromMachine(machine, privateAddress, msg);
assertNotReachable(machine, privateAddress, msg);
}
assertNotNull(subnetIp, msg);
assertReachableFromMachine(machine, subnetIp, msg);
// hostname is reachable from inside; not necessarily reachable from outside
assertNotNull(hostname, msg);
assertReachableFromMachine(machine, hostname, msg);
assertNotNull(subnetHostname, msg);
assertReachableFromMachine(machine, subnetHostname, msg);
}
@Test(groups = {"Live"})
protected void testRackspaceAddresses() throws Exception {
jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
machine = createRackspaceMachine(ImmutableMap.<String,Object>of());
assertSshable(machine);
String locationAddress = machine.getAddress().getHostAddress();
InetAddress address = machine.getAddress();
Set<String> publicAddresses = machine.getPublicAddresses();
Set<String> privateAddresses = machine.getPrivateAddresses();
String subnetIp = machine.getSubnetIp();
String hostname = machine.getHostname();
String subnetHostname = machine.getSubnetHostname();
String msg = "locationAddress="+locationAddress+"; address="+address+"; publicAddrs="+publicAddresses+"; privateAddrs="+privateAddresses+"; subnetIp="+subnetIp+"; hostname="+hostname+"; subnetHostname="+subnetHostname;
LOG.info("node: "+msg);
// On Rackspace, IP is accessible from inside and outside.
assertReachable(machine, locationAddress, msg);
assertReachableFromMachine(machine, locationAddress, msg);
assertReachable(machine, address, msg);
assertTrue(publicAddresses.size() > 0, msg);
for (String publicAddress: publicAddresses) {
assertReachable(machine, publicAddress, msg);
}
// On Rackspace, don't care if no private addresses
for (String privateAddress: privateAddresses) {
assertReachableFromMachine(machine, privateAddress, msg);
assertNotReachable(machine, privateAddress, msg);
}
assertNotNull(subnetIp, msg);
assertReachableFromMachine(machine, subnetIp, msg);
// hostname is reachable from inside; not necessarily reachable from outside
assertNotNull(hostname, msg);
assertReachableFromMachine(machine, hostname, msg);
assertNotNull(subnetHostname, msg);
assertReachableFromMachine(machine, subnetHostname, msg);
}
private void assertReachable(SshMachineLocation machine, InetAddress addr, String msg) {
assertReachable(machine, addr.getHostAddress(), msg);
}
private void assertReachable(SshMachineLocation machine, String addr, String msg) {
assertReachability(true, machine, addr, msg);
}
private void assertNotReachable(SshMachineLocation machine, String addr, String msg) {
assertReachability(false, machine, addr, msg);
}
private void assertReachability(boolean expectedReachable, SshMachineLocation machine, String addr, String msg) {
SshMachineLocation tmpMachine = managementContext.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
.configure(machine.config().getBag().getAllConfig())
.configure("address", addr));
try {
boolean sshable = tmpMachine.isSshable();
assertEquals(sshable, expectedReachable, addr+" not sshable; "+msg);
} finally {
Locations.unmanage(tmpMachine);
}
}
// TODO Assumes that "ping" will work; i.e. that ICMP is not firewall'ed
private void assertReachableFromMachine(SshMachineLocation machine, String addr, String msg) {
OutputStream outStream = new ByteArrayOutputStream();
OutputStream errStream = new ByteArrayOutputStream();
int result = machine.execScript(MutableMap.of("out", outStream, "err", errStream), "reach "+addr, ImmutableList.of("ping -c 1 "+addr));
String outString = outStream.toString();
String errString = errStream.toString();
assertEquals(result, 0, "result="+0+"; err="+errString+"; out="+outString+"; msg="+msg);
}
@Override
protected void releaseMachine(JcloudsSshMachineLocation machine) {
jcloudsLocation.release(machine);
}
private JcloudsSshMachineLocation createEc2Machine(Map<String,? extends Object> conf) throws Exception {
return obtainMachine(MutableMap.<String,Object>builder()
.putAll(conf)
.putIfAbsent("imageId", AWS_EC2_CENTOS_IMAGE_ID)
.putIfAbsent("hardwareId", AWS_EC2_SMALL_HARDWARE_ID)
.putIfAbsent("inboundPorts", ImmutableList.of(22))
.build());
}
private JcloudsSshMachineLocation createRackspaceMachine(Map<String,? extends Object> conf) throws Exception {
return obtainMachine(MutableMap.<String,Object>builder()
.putAll(conf)
.putIfAbsent("inboundPorts", ImmutableList.of(22))
.build());
}
protected void assertSshable(Map<?,?> machineConfig) {
SshMachineLocation machineWithThatConfig = managementContext.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
.configure(machineConfig));
try {
assertSshable(machineWithThatConfig);
} finally {
Streams.closeQuietly(machineWithThatConfig);
}
}
}