diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java index e48554fbb7..5054f6ea8b 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java @@ -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.checkState; +import static com.google.common.base.Predicates.and; 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.find; import static com.google.common.collect.Iterables.transform; @@ -37,6 +39,7 @@ import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; +import com.google.common.base.Optional; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Hardware; @@ -124,14 +127,14 @@ public class ServerInRegionToNodeMetadata implements Function isFloatingAddress = new Predicate
() { + public boolean apply(Address in) { + final Optional addrType = in.getType(); + return addrType.isPresent() && "floating".equals(addrType.get()); + } + }; + public static final Predicate
isPrivateAddress = new Predicate
() { public boolean apply(Address in) { return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr()); diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Address.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Address.java index c57136c1b5..1de3d9302c 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Address.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Address.java @@ -22,6 +22,10 @@ import java.beans.ConstructorProperties; import com.google.common.base.Objects; 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 @@ -50,7 +54,10 @@ public class Address { protected String addr; protected int version; - + protected String macAddr; + protected String type; + + /** * @see Address#getAddr() */ @@ -67,14 +74,26 @@ public class Address { 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() { - return new Address(addr, version); + return new Address(addr, version, macAddr, type); } public T fromAddress(Address in) { return this .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 int version; + @Named("OS-EXT-IPS-MAC:mac_addr") + private final Optional macAddr; + @Named("OS-EXT-IPS:type") + private final Optional type; @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.version = version; + this.macAddr = Optional.fromNullable(macAddr); + this.type = Optional.fromNullable(type); } /** @@ -110,9 +135,17 @@ public class Address { return this.version; } + public Optional getMacAddr() { + return this.macAddr; + } + + public Optional getType() { + return this.type; + } + @Override public int hashCode() { - return Objects.hashCode(addr, version); + return Objects.hashCode(addr, version, macAddr, type); } @Override @@ -121,12 +154,14 @@ public class Address { if (obj == null || getClass() != obj.getClass()) return false; Address that = Address.class.cast(obj); 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() { 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 diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java index e602f54b86..eadf03345d 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java @@ -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.regionscoped.ServerInRegion; 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.v2_0.domain.Link; import org.jclouds.openstack.v2_0.domain.Resource; @@ -226,6 +227,30 @@ public class ServerInRegionToNodeMetadataTest { 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.> ofInstance(ImmutableSet.of(existingImage)), + Suppliers.> 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 private void checkHardwareAndImageStatus(Hardware expectedHardware, Hardware existingHardware, String expectedImageId, OperatingSystem expectedOs, Image existingImage) { diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerDetailsStatesTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerDetailsStatesTest.java index 4461857844..81e6fd3b2b 100755 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerDetailsStatesTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerDetailsStatesTest.java @@ -130,7 +130,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest { .hypervisorHostName("rdohavana.localdomain").build() ) .addresses(ImmutableMultimap.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(), Server.builder() .links( @@ -168,7 +169,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest { .instanceName("instance-00000006").build() ) .addresses(ImmutableMultimap.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(), Server.builder() .links( @@ -209,7 +211,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest { .hypervisorHostName("rdohavana.localdomain").build() ) .addresses(ImmutableMultimap.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(), Server.builder() .links( @@ -250,7 +253,8 @@ public class ParseServerDetailsStatesTest extends BaseSetParserTest { .hypervisorHostName("rdohavana.localdomain").build() ) .addresses(ImmutableMultimap.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() ); } diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerWithAddressExtensionsTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerWithAddressExtensionsTest.java new file mode 100644 index 0000000000..d20c091353 --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseServerWithAddressExtensionsTest.java @@ -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 { + + @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.of("jclouds-group", "cloudts")) + .addresses(ImmutableMultimap.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()); + } +} diff --git a/apis/openstack-nova/src/test/resources/server_details_with_address_ext.json b/apis/openstack-nova/src/test/resources/server_details_with_address_ext.json new file mode 100755 index 0000000000..da2472db8d --- /dev/null +++ b/apis/openstack-nova/src/test/resources/server_details_with_address_ext.json @@ -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" + } +} \ No newline at end of file