[JCLOUDS-1079] Make Floating IPs public in the NodeMetadata in openstack-nova provider

This commit is contained in:
Josef Cacek 2016-02-18 00:08:21 +01:00 committed by Ignasi Barrera
parent 8bbcfed312
commit e0ab5d848a
6 changed files with 272 additions and 14 deletions

View File

@ -18,7 +18,9 @@ package org.jclouds.openstack.nova.v2_0.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.not; import static com.google.common.base.Predicates.not;
import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
@ -37,6 +39,7 @@ import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import com.google.common.base.Optional;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
@ -124,14 +127,14 @@ public class ServerInRegionToNodeMetadata implements Function<ServerInRegion, No
builder.publicAddresses( builder.publicAddresses(
filter( filter(
transform( transform(
filter(addresses, not(isPrivateAddress)), filter(addresses, or(isFloatingAddress, not(isPrivateAddress))),
AddressToStringTransformationFunction.INSTANCE), AddressToStringTransformationFunction.INSTANCE),
isInet4Address)); isInet4Address));
builder.privateAddresses( builder.privateAddresses(
filter( filter(
transform( transform(
filter(addresses, isPrivateAddress), filter(addresses, and(not(isFloatingAddress), isPrivateAddress)),
AddressToStringTransformationFunction.INSTANCE), AddressToStringTransformationFunction.INSTANCE),
isInet4Address)); isInet4Address));
@ -144,6 +147,13 @@ public class ServerInRegionToNodeMetadata implements Function<ServerInRegion, No
return builder.build(); return builder.build();
} }
public static final Predicate<Address> isFloatingAddress = new Predicate<Address>() {
public boolean apply(Address in) {
final Optional<String> addrType = in.getType();
return addrType.isPresent() && "floating".equals(addrType.get());
}
};
public static final Predicate<Address> isPrivateAddress = new Predicate<Address>() { public static final Predicate<Address> isPrivateAddress = new Predicate<Address>() {
public boolean apply(Address in) { public boolean apply(Address in) {
return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr()); return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());

View File

@ -22,6 +22,10 @@ import java.beans.ConstructorProperties;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import org.jclouds.javax.annotation.Nullable;
import javax.inject.Named;
/** /**
* IP address * IP address
@ -50,6 +54,9 @@ public class Address {
protected String addr; protected String addr;
protected int version; protected int version;
protected String macAddr;
protected String type;
/** /**
* @see Address#getAddr() * @see Address#getAddr()
@ -67,14 +74,26 @@ public class Address {
return self(); return self();
} }
public T macAddr(String macAddr) {
this.macAddr = macAddr;
return self();
}
public T type(String type) {
this.type = type;
return self();
}
public Address build() { public Address build() {
return new Address(addr, version); return new Address(addr, version, macAddr, type);
} }
public T fromAddress(Address in) { public T fromAddress(Address in) {
return this return this
.addr(in.getAddr()) .addr(in.getAddr())
.version(in.getVersion()); .version(in.getVersion())
.macAddr(in.getMacAddr().orNull())
.type(in.getType().orNull());
} }
} }
@ -87,13 +106,19 @@ public class Address {
private final String addr; private final String addr;
private final int version; private final int version;
@Named("OS-EXT-IPS-MAC:mac_addr")
private final Optional<String> macAddr;
@Named("OS-EXT-IPS:type")
private final Optional<String> type;
@ConstructorProperties({ @ConstructorProperties({
"addr", "version" "addr", "version", "OS-EXT-IPS-MAC:mac_addr", "OS-EXT-IPS:type"
}) })
protected Address(String addr, int version) { protected Address(String addr, int version, @Nullable String macAddr, @Nullable String type) {
this.addr = checkNotNull(addr, "addr"); this.addr = checkNotNull(addr, "addr");
this.version = version; this.version = version;
this.macAddr = Optional.fromNullable(macAddr);
this.type = Optional.fromNullable(type);
} }
/** /**
@ -110,9 +135,17 @@ public class Address {
return this.version; return this.version;
} }
public Optional<String> getMacAddr() {
return this.macAddr;
}
public Optional<String> getType() {
return this.type;
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(addr, version); return Objects.hashCode(addr, version, macAddr, type);
} }
@Override @Override
@ -121,12 +154,14 @@ public class Address {
if (obj == null || getClass() != obj.getClass()) return false; if (obj == null || getClass() != obj.getClass()) return false;
Address that = Address.class.cast(obj); Address that = Address.class.cast(obj);
return Objects.equal(this.addr, that.addr) return Objects.equal(this.addr, that.addr)
&& Objects.equal(this.version, that.version); && Objects.equal(this.version, that.version)
&& Objects.equal(this.macAddr, that.macAddr)
&& Objects.equal(this.type, that.type);
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this)
.add("addr", addr).add("version", version); .add("addr", addr).add("version", version).add("macAddr", macAddr.or("")).add("type", type.or(""));
} }
@Override @Override

View File

@ -40,6 +40,7 @@ import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextM
import org.jclouds.openstack.nova.v2_0.domain.Server; import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion; import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerTest; import org.jclouds.openstack.nova.v2_0.parse.ParseServerTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerWithAddressExtensionsTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerWithoutImageTest; import org.jclouds.openstack.nova.v2_0.parse.ParseServerWithoutImageTest;
import org.jclouds.openstack.v2_0.domain.Link; import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Resource; import org.jclouds.openstack.v2_0.domain.Resource;
@ -226,6 +227,30 @@ public class ServerInRegionToNodeMetadataTest {
assertNull(convertedNodeMetadata.getImageId()); assertNull(convertedNodeMetadata.getImageId());
} }
@Test
public void testFloatingIp() {
Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
.providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
.operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
.providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
.location(region).build();
Server serverToConvert = new ParseServerWithAddressExtensionsTest().expected();
ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex,
Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.of(existingImage)),
Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet.of(existingHardware)),
namingConvention);
NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("172.16.130.24"));
assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("10.8.54.75"));
}
// TODO: clean up this syntax // TODO: clean up this syntax
private void checkHardwareAndImageStatus(Hardware expectedHardware, Hardware existingHardware, private void checkHardwareAndImageStatus(Hardware expectedHardware, Hardware existingHardware,
String expectedImageId, OperatingSystem expectedOs, Image existingImage) { String expectedImageId, OperatingSystem expectedOs, Image existingImage) {

View File

@ -130,7 +130,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest<Server> {
.hypervisorHostName("rdohavana.localdomain").build() .hypervisorHostName("rdohavana.localdomain").build()
) )
.addresses(ImmutableMultimap.<String, Address>builder() .addresses(ImmutableMultimap.<String, Address>builder()
.putAll("public", Address.createV4("172.24.4.232")).build() .putAll("public", Address.builder().addr("172.24.4.232").version(4)
.macAddr("fa:16:3e:df:22:1b").type("fixed").build()).build()
).build(), ).build(),
Server.builder() Server.builder()
.links( .links(
@ -168,7 +169,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest<Server> {
.instanceName("instance-00000006").build() .instanceName("instance-00000006").build()
) )
.addresses(ImmutableMultimap.<String, Address>builder() .addresses(ImmutableMultimap.<String, Address>builder()
.putAll("public", Address.createV4("172.24.4.229")).build() .putAll("public", Address.builder().addr("172.24.4.229").version(4)
.macAddr("fa:16:3e:cb:56:d6").type("fixed").build()).build()
).build(), ).build(),
Server.builder() Server.builder()
.links( .links(
@ -209,7 +211,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest<Server> {
.hypervisorHostName("rdohavana.localdomain").build() .hypervisorHostName("rdohavana.localdomain").build()
) )
.addresses(ImmutableMultimap.<String, Address>builder() .addresses(ImmutableMultimap.<String, Address>builder()
.putAll("public", Address.createV4("172.24.4.227")).build() .putAll("public", Address.builder().addr("172.24.4.227").version(4)
.macAddr("fa:16:3e:18:fe:c8").type("fixed").build()).build()
).build(), ).build(),
Server.builder() Server.builder()
.links( .links(
@ -250,7 +253,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest<Server> {
.hypervisorHostName("rdohavana.localdomain").build() .hypervisorHostName("rdohavana.localdomain").build()
) )
.addresses(ImmutableMultimap.<String, Address>builder() .addresses(ImmutableMultimap.<String, Address>builder()
.putAll("public", Address.createV4("172.24.4.228")).build() .putAll("public", Address.builder().addr("172.24.4.228").version(4)
.macAddr("fa:16:3e:64:1a:d5").type("fixed").build()).build()
).build() ).build()
); );
} }

View File

@ -0,0 +1,107 @@
/*
* 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.jclouds.openstack.nova.v2_0.parse;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.openstack.nova.v2_0.domain.Address;
import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
import org.jclouds.openstack.nova.v2_0.domain.ServerExtendedStatus;
import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Link.Relation;
import org.jclouds.openstack.v2_0.domain.Resource;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.net.URI;
@Test(groups = "unit", testName = "ParseServerWithAddressExtensionsTest")
public class ParseServerWithAddressExtensionsTest extends BaseItemParserTest<Server> {
@Override
public String resource() {
return "/server_details_with_address_ext.json";
}
@Override
@SelectJson("server")
@Consumes(MediaType.APPLICATION_JSON)
public Server expected() {
return Server
.builder()
.id("0bdc3a8d-3a96-4ccc-bb40-715537a7df7b")
.tenantId("cac29c920a6149aabe499757b6ba81c7")
.userId("ed15e338032f4a2c85b7fa80e40b9917")
.name("cloudts-f07")
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2016-02-17T14:48:00Z"))
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2016-02-17T14:46:13Z"))
.hostId("18a9cd55f76c520dcad6c31d5b2b8f4c921979629c0274c0f7d2de39")
.status(Status.ACTIVE)
.image(
Resource
.builder()
.id("9a9f496a-f5c2-4286-81a4-98189a48777a")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/images/9a9f496a-f5c2-4286-81a4-98189a48777a")))
.build())
.flavor(
Resource
.builder()
.id("3")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/flavors/3")))
.build())
.links(
Link.create(
Relation.SELF,
URI.create("http://openstack:8774/v2/cac29c920a6149aabe499757b6ba81c7/servers/0bdc3a8d-3a96-4ccc-bb40-715537a7df7b")),
Link.create(
Relation.BOOKMARK,
URI.create("http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/servers/0bdc3a8d-3a96-4ccc-bb40-715537a7df7b")))
.metadata(ImmutableMap.<String, String>of("jclouds-group", "cloudts"))
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("jenkins",
Address.builder().version(4).addr("172.16.130.24").macAddr("fa:16:3e:bf:82:43").type("fixed").build(),
Address.builder().version(4).addr("10.8.54.75").macAddr("fa:16:3e:bf:82:43").type("floating").build())
.build())
.diskConfig("MANUAL")
.configDrive("")
.availabilityZone("nova")
.accessIPv4("")
.accessIPv6("")
.keyName("jenkins")
.extendedStatus(ServerExtendedStatus.builder().vmState("active").powerState(1).build())
.build();
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

@ -0,0 +1,77 @@
{
"server": {
"OS-DCF:diskConfig": "MANUAL",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2016-02-17T14:48:00.000000",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "",
"accessIPv6": "",
"addresses": {
"jenkins": [
{
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:bf:82:43",
"OS-EXT-IPS:type": "fixed",
"addr": "172.16.130.24",
"version": 4
},
{
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:bf:82:43",
"OS-EXT-IPS:type": "floating",
"addr": "10.8.54.75",
"version": 4
}
]
},
"config_drive": "",
"created": "2016-02-17T14:46:13Z",
"flavor": {
"id": "3",
"links": [
{
"href": "http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/flavors/3",
"rel": "bookmark"
}
]
},
"hostId": "18a9cd55f76c520dcad6c31d5b2b8f4c921979629c0274c0f7d2de39",
"id": "0bdc3a8d-3a96-4ccc-bb40-715537a7df7b",
"image": {
"id": "9a9f496a-f5c2-4286-81a4-98189a48777a",
"links": [
{
"href": "http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/images/9a9f496a-f5c2-4286-81a4-98189a48777a",
"rel": "bookmark"
}
]
},
"key_name": "jenkins",
"links": [
{
"href": "http://openstack:8774/v2/cac29c920a6149aabe499757b6ba81c7/servers/0bdc3a8d-3a96-4ccc-bb40-715537a7df7b",
"rel": "self"
},
{
"href": "http://openstack:8774/cac29c920a6149aabe499757b6ba81c7/servers/0bdc3a8d-3a96-4ccc-bb40-715537a7df7b",
"rel": "bookmark"
}
],
"metadata": {
"jclouds-group": "cloudts"
},
"name": "cloudts-f07",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "allow-all"
}
],
"status": "ACTIVE",
"tenant_id": "cac29c920a6149aabe499757b6ba81c7",
"updated": "2016-02-17T14:48:00Z",
"user_id": "ed15e338032f4a2c85b7fa80e40b9917"
}
}