mirror of https://github.com/apache/jclouds.git
[JCLOUDS-1382] improve usage of Neutron capabilities from Nova
- move Neutron FloatingIP API from extension to feature - introduce FloatingIpForServer as abstract domain object to represents Nova and Neutron objects - manage floating ip cache and its invalidation
This commit is contained in:
parent
88c84af878
commit
50ae6828f5
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
import javax.ws.rs.Path;
|
||||
|
||||
import org.jclouds.location.Region;
|
||||
import org.jclouds.openstack.neutron.v2.extensions.FloatingIPApi;
|
||||
import org.jclouds.openstack.neutron.v2.features.FloatingIPApi;
|
||||
import org.jclouds.openstack.neutron.v2.extensions.RouterApi;
|
||||
import org.jclouds.openstack.neutron.v2.features.SecurityGroupApi;
|
||||
import org.jclouds.openstack.neutron.v2.extensions.lbaas.v1.LBaaSApi;
|
||||
|
@ -88,6 +88,12 @@ public interface NeutronApi extends Closeable {
|
|||
@Delegate
|
||||
SecurityGroupApi getSecurityGroupApi(@EndpointParam(parser = VersionAwareRegionToEndpoint.class) String region);
|
||||
|
||||
/**
|
||||
* Provides access to Floating IP features.
|
||||
*/
|
||||
@Delegate
|
||||
FloatingIPApi getFloatingIPApi(@EndpointParam(parser = VersionAwareRegionToEndpoint.class) String region);
|
||||
|
||||
/**
|
||||
* Provides access to Router features.
|
||||
*
|
||||
|
@ -98,16 +104,6 @@ public interface NeutronApi extends Closeable {
|
|||
@Delegate
|
||||
Optional<RouterApi> getRouterApi(@EndpointParam(parser = VersionAwareRegionToEndpoint.class) String region);
|
||||
|
||||
/**
|
||||
* Provides access to Floating IP features.
|
||||
*
|
||||
* <h3>NOTE</h3>
|
||||
* This API is an extension that may or may not be present in your OpenStack cloud. Use the Optional return type
|
||||
* to determine if it is present.
|
||||
*/
|
||||
@Delegate
|
||||
Optional<FloatingIPApi> getFloatingIPApi(@EndpointParam(parser = VersionAwareRegionToEndpoint.class) String region);
|
||||
|
||||
/**
|
||||
* Provides access to LBaaS features.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,8 @@ public class FloatingIP {
|
|||
private String id;
|
||||
@Named("router_id")
|
||||
private String routerId;
|
||||
@Named("project_id")
|
||||
private String projectId;
|
||||
@Named("tenant_id")
|
||||
private String tenantId;
|
||||
// Only mandatory attribute when creating
|
||||
|
@ -45,21 +47,25 @@ public class FloatingIP {
|
|||
private String floatingIpAddress;
|
||||
@Named("port_id")
|
||||
private String portId;
|
||||
@Named("availability_zone")
|
||||
private String availabilityZone;
|
||||
|
||||
/**
|
||||
* Deserialization constructor
|
||||
*/
|
||||
@ConstructorProperties({"id", "router_id", "tenant_id", "floating_network_id", "fixed_ip_address",
|
||||
"floating_ip_address", "port_id"})
|
||||
private FloatingIP(String id, String routerId, String tenantId, String floatingNetworkId, String fixedIpAddress,
|
||||
String floatingIpAddress, String portId) {
|
||||
@ConstructorProperties({"id", "router_id", "project_id", "tenant_id", "floating_network_id", "fixed_ip_address",
|
||||
"floating_ip_address", "port_id", "availability_zone"})
|
||||
private FloatingIP(String id, String routerId, String projectId, String tenantId, String floatingNetworkId, String fixedIpAddress,
|
||||
String floatingIpAddress, String portId, String availabilityZone) {
|
||||
this.id = id;
|
||||
this.routerId = routerId;
|
||||
this.projectId = projectId;
|
||||
this.tenantId = tenantId;
|
||||
this.floatingNetworkId = floatingNetworkId;
|
||||
this.fixedIpAddress = fixedIpAddress;
|
||||
this.floatingIpAddress = floatingIpAddress;
|
||||
this.portId = portId;
|
||||
this.availabilityZone = availabilityZone;
|
||||
}
|
||||
|
||||
private FloatingIP() {}
|
||||
|
@ -68,8 +74,8 @@ public class FloatingIP {
|
|||
* @param floatingIP The floating IP to copy from
|
||||
*/
|
||||
private FloatingIP(FloatingIP floatingIP) {
|
||||
this(floatingIP.id, floatingIP.routerId, floatingIP.tenantId, floatingIP.floatingNetworkId,
|
||||
floatingIP.fixedIpAddress, floatingIP.floatingIpAddress, floatingIP.portId);
|
||||
this(floatingIP.id, floatingIP.routerId, floatingIP.projectId, floatingIP.tenantId, floatingIP.floatingNetworkId,
|
||||
floatingIP.fixedIpAddress, floatingIP.floatingIpAddress, floatingIP.portId, floatingIP.availabilityZone);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,6 +94,14 @@ public class FloatingIP {
|
|||
return routerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the project id of the Floating IP
|
||||
*/
|
||||
@Nullable
|
||||
public String getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tenant id of the Floating IP
|
||||
*/
|
||||
|
@ -128,6 +142,14 @@ public class FloatingIP {
|
|||
return portId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the availability zone for this floating IP
|
||||
*/
|
||||
@Nullable
|
||||
public String getAvailabilityZone() {
|
||||
return availabilityZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
|
@ -139,17 +161,20 @@ public class FloatingIP {
|
|||
|
||||
return Objects.equal(this.id, that.id) &&
|
||||
Objects.equal(this.routerId, that.routerId) &&
|
||||
Objects.equal(this.projectId, that.projectId) &&
|
||||
Objects.equal(this.tenantId, that.tenantId) &&
|
||||
Objects.equal(this.floatingNetworkId, that.floatingNetworkId) &&
|
||||
Objects.equal(this.fixedIpAddress, that.fixedIpAddress) &&
|
||||
Objects.equal(this.floatingIpAddress, that.floatingIpAddress) &&
|
||||
Objects.equal(this.portId, that.portId);
|
||||
Objects.equal(this.portId, that.portId) &&
|
||||
Objects.equal(this.availabilityZone, that.availabilityZone);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, routerId, tenantId, floatingNetworkId, fixedIpAddress, floatingIpAddress,
|
||||
portId);
|
||||
return Objects.hashCode(id, routerId, projectId, tenantId, floatingNetworkId, fixedIpAddress, floatingIpAddress,
|
||||
portId, availabilityZone);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,11 +182,13 @@ public class FloatingIP {
|
|||
return MoreObjects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("routerId", routerId)
|
||||
.add("projectId", projectId)
|
||||
.add("tenantId", tenantId)
|
||||
.add("floatingNetworkId", floatingNetworkId)
|
||||
.add("fixedIpAddress", fixedIpAddress)
|
||||
.add("floatingIpAddress", floatingIpAddress)
|
||||
.add("portId", portId)
|
||||
.add("availabilityZone", availabilityZone)
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
@ -191,6 +218,17 @@ public class FloatingIP {
|
|||
|
||||
protected abstract ParameterizedBuilderType self();
|
||||
|
||||
/**
|
||||
* Provide the project ID for this Floating IP.
|
||||
*
|
||||
* @return the Builder.
|
||||
* @see FloatingIP#getProjectId() ()
|
||||
*/
|
||||
public ParameterizedBuilderType projectId(String projectId) {
|
||||
floatingIP.projectId = projectId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the tenantId for this Floating IP. Admin-only.
|
||||
* When keystone is enabled, it is not mandatory to specify tenant_id for resources in create requests, as the
|
||||
|
@ -249,6 +287,18 @@ public class FloatingIP {
|
|||
floatingIP.portId = portId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the availability zone for this Floating IP.
|
||||
*
|
||||
* @return the Builder.
|
||||
* @see FloatingIP#getAvailabilityZone()
|
||||
*/
|
||||
public ParameterizedBuilderType availabilityZone(String availabilityZone) {
|
||||
floatingIP.availabilityZone = availabilityZone;
|
||||
return self();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class CreateBuilder extends Builder<CreateBuilder> {
|
||||
|
|
|
@ -47,6 +47,8 @@ public class Network {
|
|||
private Boolean shared;
|
||||
@Named("tenant_id")
|
||||
private String tenantId;
|
||||
@Named("availability_zone")
|
||||
private String availabilityZone;
|
||||
|
||||
// providernet.py: Provider Networks Extension
|
||||
@Named("provider:network_type")
|
||||
|
@ -85,12 +87,12 @@ public class Network {
|
|||
@Named("flavor:network")
|
||||
private String networkFlavor;
|
||||
|
||||
@ConstructorProperties({"id", "status", "subnets", "name", "admin_state_up", "shared", "tenant_id",
|
||||
@ConstructorProperties({"id", "status", "subnets", "name", "admin_state_up", "shared", "tenant_id", "availability_zone",
|
||||
"provider:network_type", "provider:physical_network", "provider:segmentation_id", "router:external",
|
||||
"port_security_enabled", "n1kv:profile_id", "n1kv:multicast_ip", "n1kv:segment_add", "n1kv:segment_del",
|
||||
"n1kv:member_segments", "segments", "flavor:network"})
|
||||
private Network(String id, NetworkStatus status, ImmutableSet<String> subnets, String name, Boolean adminStateUp,
|
||||
Boolean shared, String tenantId, NetworkType networkType, String physicalNetworkName, Integer segmentationId,
|
||||
Boolean shared, String tenantId, String availabilityZone, NetworkType networkType, String physicalNetworkName, Integer segmentationId,
|
||||
Boolean external, Boolean portSecurity, String profileId, String multicastIp, String segmentAdd,
|
||||
String segmentDel, String memberSegments, ImmutableSet<NetworkSegment> segments, String networkFlavor) {
|
||||
// No checkNotNulls. With Neutron, any of these properties can be left null when used in an update.
|
||||
|
@ -101,6 +103,7 @@ public class Network {
|
|||
this.adminStateUp = adminStateUp;
|
||||
this.shared = shared;
|
||||
this.tenantId = tenantId;
|
||||
this.availabilityZone = availabilityZone;
|
||||
this.networkType = networkType;
|
||||
this.physicalNetworkName = physicalNetworkName;
|
||||
this.segmentationId = segmentationId;
|
||||
|
@ -132,6 +135,7 @@ public class Network {
|
|||
network.adminStateUp,
|
||||
network.shared,
|
||||
network.tenantId,
|
||||
network.availabilityZone,
|
||||
network.networkType,
|
||||
network.physicalNetworkName,
|
||||
network.segmentationId,
|
||||
|
@ -205,6 +209,14 @@ public class Network {
|
|||
return tenantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the availability zone of the Network
|
||||
*/
|
||||
@Nullable
|
||||
public String getAvailabilityZone() {
|
||||
return availabilityZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the networkType of the Network
|
||||
*/
|
||||
|
@ -304,7 +316,7 @@ public class Network {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, status, subnets, name, adminStateUp, shared, tenantId, networkType,
|
||||
return Objects.hashCode(id, status, subnets, name, adminStateUp, shared, tenantId, availabilityZone, networkType,
|
||||
physicalNetworkName, segmentationId, external, portSecurity, profileId, multicastIp, segmentAdd, segmentDel,
|
||||
memberSegments, segments, networkFlavor);
|
||||
}
|
||||
|
@ -323,6 +335,7 @@ public class Network {
|
|||
&& Objects.equal(this.adminStateUp, that.adminStateUp)
|
||||
&& Objects.equal(this.shared, that.shared)
|
||||
&& Objects.equal(this.tenantId, that.tenantId)
|
||||
&& Objects.equal(this.availabilityZone, that.availabilityZone)
|
||||
&& Objects.equal(this.networkType, that.networkType)
|
||||
&& Objects.equal(this.physicalNetworkName, that.physicalNetworkName)
|
||||
&& Objects.equal(this.segmentationId, that.segmentationId)
|
||||
|
@ -347,6 +360,7 @@ public class Network {
|
|||
.add("adminStateUp", adminStateUp)
|
||||
.add("shared", shared)
|
||||
.add("tenantId", tenantId)
|
||||
.add("availabilityZone", availabilityZone)
|
||||
.add("networkType", networkType)
|
||||
.add("physicalNetworkName", physicalNetworkName)
|
||||
.add("segmentationId", segmentationId)
|
||||
|
@ -436,6 +450,17 @@ public class Network {
|
|||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the availabilityZone to the Network's Builder.
|
||||
*
|
||||
* @return the Builder.
|
||||
* @see Network#getAvailabilityZone() ()
|
||||
*/
|
||||
public ParameterizedBuilderType availabilityZone(String availabilityZone) {
|
||||
network.availabilityZone = availabilityZone;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the networkType to the Network's Builder.
|
||||
*
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package org.jclouds.openstack.neutron.v2.domain;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import org.jclouds.openstack.v2_0.domain.Link;
|
||||
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
|
||||
|
||||
|
@ -33,4 +35,25 @@ public class Networks extends PaginatedCollection<Network> {
|
|||
protected Networks(Iterable<Network> networks, Iterable<Link> networksLinks) {
|
||||
super(networks, networksLinks);
|
||||
}
|
||||
|
||||
public static class Predicates {
|
||||
|
||||
public static Predicate<Network> externalNetworks(final String availabilityZone) {
|
||||
return new Predicate<Network>() {
|
||||
@Override
|
||||
public boolean apply(Network network) {
|
||||
return availabilityZone.equals(network.getAvailabilityZone()) && network.getExternal();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Predicate<Network> namedNetworks(final Set<String> names) {
|
||||
return new Predicate<Network>() {
|
||||
@Override
|
||||
public boolean apply(Network network) {
|
||||
return names.contains(network.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.neutron.v2.extensions;
|
||||
package org.jclouds.openstack.neutron.v2.features;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -37,9 +37,7 @@ import org.jclouds.openstack.neutron.v2.domain.FloatingIPs;
|
|||
import org.jclouds.openstack.neutron.v2.fallbacks.EmptyFloatingIPsFallback;
|
||||
import org.jclouds.openstack.neutron.v2.functions.FloatingIPsToPagedIterable;
|
||||
import org.jclouds.openstack.neutron.v2.functions.ParseFloatingIPs;
|
||||
import org.jclouds.openstack.v2_0.ServiceType;
|
||||
import org.jclouds.openstack.v2_0.options.PaginationOptions;
|
||||
import org.jclouds.openstack.v2_0.services.Extension;
|
||||
import org.jclouds.rest.annotations.Fallback;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
|
@ -61,7 +59,6 @@ import com.google.common.annotations.Beta;
|
|||
@Path("/floatingips")
|
||||
@RequestFilters(AuthenticateRequest.class)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Extension(of = ServiceType.NETWORK, namespace = ExtensionNamespaces.L3_ROUTER, name = "Neutron L3 Router", alias = "router")
|
||||
public interface FloatingIPApi {
|
||||
|
||||
/**
|
|
@ -22,7 +22,7 @@ import org.jclouds.collect.IterableWithMarker;
|
|||
import org.jclouds.collect.internal.Arg0ToPagedIterable;
|
||||
import org.jclouds.openstack.neutron.v2.NeutronApi;
|
||||
import org.jclouds.openstack.neutron.v2.domain.FloatingIP;
|
||||
import org.jclouds.openstack.neutron.v2.extensions.FloatingIPApi;
|
||||
import org.jclouds.openstack.neutron.v2.features.FloatingIPApi;
|
||||
import org.jclouds.openstack.v2_0.options.PaginationOptions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -44,7 +44,7 @@ public class FloatingIPsToPagedIterable extends Arg0ToPagedIterable.FromCaller<F
|
|||
@Override
|
||||
protected Function<Object, IterableWithMarker<FloatingIP>> markerToNextForArg0(Optional<Object> arg0) {
|
||||
String region = arg0.isPresent() ? arg0.get().toString() : null;
|
||||
final FloatingIPApi floatingIPApi = api.getFloatingIPApi(region).get();
|
||||
final FloatingIPApi floatingIPApi = api.getFloatingIPApi(region);
|
||||
return new Function<Object, IterableWithMarker<FloatingIP>>() {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.jclouds.openstack.neutron.v2.domain.FloatingIP;
|
|||
import org.jclouds.openstack.neutron.v2.domain.UpdateFirewall;
|
||||
import org.jclouds.openstack.neutron.v2.domain.UpdateFirewallPolicy;
|
||||
import org.jclouds.openstack.neutron.v2.domain.UpdateFirewallRule;
|
||||
import org.jclouds.openstack.neutron.v2.features.FloatingIPApi;
|
||||
import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest;
|
||||
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
|
||||
import org.jclouds.openstack.v2_0.options.PaginationOptions;
|
||||
|
@ -130,13 +131,12 @@ public class FWaaSApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testListPagedFirewall() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/floatingip_list_response_paged1.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/floatingip_list_response_paged2.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
// Note: Lazy! Have to actually look at the collection.
|
||||
List<FloatingIP> floatingIPs = api.list().concat().toList();
|
||||
|
@ -144,9 +144,8 @@ public class FWaaSApiMockTest extends BaseNeutronApiMockTest {
|
|||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 4);
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
|
||||
|
||||
|
|
|
@ -15,28 +15,25 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jclouds.openstack.neutron.v2.extensions;
|
||||
package org.jclouds.openstack.neutron.v2.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import org.jclouds.openstack.neutron.v2.domain.FloatingIP;
|
||||
import org.jclouds.openstack.neutron.v2.domain.IP;
|
||||
import org.jclouds.openstack.neutron.v2.domain.Network;
|
||||
import org.jclouds.openstack.neutron.v2.domain.NetworkType;
|
||||
import org.jclouds.openstack.neutron.v2.domain.Subnet;
|
||||
import org.jclouds.openstack.neutron.v2.features.NetworkApi;
|
||||
import org.jclouds.openstack.neutron.v2.features.SubnetApi;
|
||||
import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Tests parsing and Guice wiring of RouterApi
|
||||
* Tests parsing and Guice wiring of FloatingIPApi
|
||||
*/
|
||||
@Test(groups = "live", testName = "FloatingIPApiLiveTest")
|
||||
public class FloatingIPApiLiveTest extends BaseNeutronApiLiveTest {
|
||||
|
@ -44,45 +41,33 @@ public class FloatingIPApiLiveTest extends BaseNeutronApiLiveTest {
|
|||
public void testCreateUpdateAndDeleteFloatingIP() {
|
||||
for (String region : api.getConfiguredRegions()) {
|
||||
|
||||
SubnetApi subnetApi = api.getSubnetApi(region);
|
||||
FloatingIPApi floatingIPApi = api.getFloatingIPApi(region).get();
|
||||
FloatingIPApi floatingIPApi = api.getFloatingIPApi(region);
|
||||
NetworkApi networkApi = api.getNetworkApi(region);
|
||||
|
||||
FloatingIP floatingIPGet = null;
|
||||
String ipv4SubnetId = null;
|
||||
Network network = null;
|
||||
Network network;
|
||||
|
||||
try {
|
||||
network = networkApi.create(
|
||||
Network.createBuilder("jclouds-network-test").external(true).networkType(NetworkType.LOCAL).build());
|
||||
assertNotNull(network);
|
||||
network = networkApi.list().concat().firstMatch(new Predicate<Network>() {
|
||||
@Override
|
||||
public boolean apply(Network input) {
|
||||
return input.getExternal();
|
||||
}
|
||||
}).orNull();
|
||||
|
||||
ipv4SubnetId = subnetApi.create(Subnet.createBuilder(network.getId(), "198.51.100.0/24").ipVersion(4)
|
||||
.name("JClouds-Live-IPv4-Subnet").build()).getId();
|
||||
|
||||
floatingIPApi.create(FloatingIP.createBuilder(network.getId()).build());
|
||||
if (network == null) Assert.fail("Cannot find a suitable external network. Please add it manually or contact your administrator");
|
||||
|
||||
FloatingIP floatingIP = floatingIPApi.create(FloatingIP.createBuilder(network.getId()).availabilityZone(network.getAvailabilityZone()).build());
|
||||
/* List and Get test */
|
||||
Set<FloatingIP> floatingIPs = floatingIPApi.list().concat().toSet();
|
||||
FloatingIP floatingIPList = floatingIPs.iterator().next();
|
||||
floatingIPGet = floatingIPApi.get(floatingIPList.getId());
|
||||
floatingIPGet = floatingIPApi.get(floatingIP.getId());
|
||||
|
||||
assertNotNull(floatingIPGet);
|
||||
assertEquals(floatingIPGet, floatingIPList);
|
||||
assertTrue(floatingIPs.contains(floatingIP));
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
assertTrue(floatingIPApi.delete(floatingIPGet.getId()));
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
assertTrue(subnetApi.delete(ipv4SubnetId));
|
||||
}
|
||||
finally {
|
||||
assertTrue(networkApi.delete(network.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.neutron.v2.extensions;
|
||||
package org.jclouds.openstack.neutron.v2.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
@ -45,13 +45,12 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testCreateFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(
|
||||
new MockResponse().setResponseCode(201).setBody(stringFromResource("/floatingip_create_response.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
FloatingIP.CreateFloatingIP createFip = FloatingIP.createBuilder("376da547-b977-4cfe-9cba-275c80debf57")
|
||||
.portId("ce705c24-c1ef-408a-bda3-7bbd946164ab")
|
||||
|
@ -62,9 +61,8 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "POST", uriApiVersion + "/floatingips", "/floatingip_create_request.json");
|
||||
|
||||
/*
|
||||
|
@ -87,21 +85,19 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testListSpecificPageFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/floatingip_list_response_paged1.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
FloatingIPs floatingIPs = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
|
||||
|
||||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips?limit=2&marker=abcdefg");
|
||||
|
||||
/*
|
||||
|
@ -119,13 +115,12 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testListPagedFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/floatingip_list_response_paged1.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/floatingip_list_response_paged2.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
// Note: Lazy! Have to actually look at the collection.
|
||||
List<FloatingIP> floatingIPs = api.list().concat().toList();
|
||||
|
@ -133,9 +128,8 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 4);
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
|
||||
|
||||
|
@ -154,22 +148,20 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testGetFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(
|
||||
new MockResponse().setResponseCode(201).setBody(stringFromResource("/floatingip_get_response.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
FloatingIP floatingIP = api.get("12345");
|
||||
|
||||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "GET", uriApiVersion + "/floatingips/12345");
|
||||
|
||||
/*
|
||||
|
@ -192,13 +184,12 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testUpdateFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(
|
||||
new MockResponse().setResponseCode(201).setBody(stringFromResource("/floatingip_update_response.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
FloatingIP.UpdateFloatingIP updateFloatingIP = FloatingIP.updateBuilder()
|
||||
.portId("fc861431-0e6c-4842-a0ed-e2363f9bc3a8")
|
||||
|
@ -209,9 +200,8 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "PUT", uriApiVersion + "/floatingips/12345", "/floatingip_update_request.json");
|
||||
|
||||
/*
|
||||
|
@ -228,13 +218,12 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testUpdateFloatingIPDissociate() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(
|
||||
new MockResponse().setResponseCode(201).setBody(stringFromResource("/floatingip_update_dissociate_response.json"))));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
FloatingIP.UpdateFloatingIP updateFloatingIP = FloatingIP.updateBuilder().build();
|
||||
|
||||
|
@ -243,9 +232,8 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "PUT", uriApiVersion + "/floatingips/12345", "/floatingip_update_dissociate_request.json");
|
||||
|
||||
/*
|
||||
|
@ -262,22 +250,20 @@ public class FloatingIPApiMockTest extends BaseNeutronApiMockTest {
|
|||
public void testDeleteFloatingIP() throws IOException, InterruptedException, URISyntaxException {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json"))));
|
||||
server.enqueue(addCommonHeaders(
|
||||
new MockResponse().setResponseCode(201)));
|
||||
|
||||
try {
|
||||
NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne").get();
|
||||
FloatingIPApi api = neutronApi.getFloatingIPApi("RegionOne");
|
||||
|
||||
boolean result = api.delete("12345");
|
||||
|
||||
/*
|
||||
* Check request
|
||||
*/
|
||||
assertEquals(server.getRequestCount(), 3);
|
||||
assertEquals(server.getRequestCount(), 2);
|
||||
assertAuthentication(server);
|
||||
assertExtensions(server, uriApiVersion + "");
|
||||
assertRequest(server.takeRequest(), "DELETE", uriApiVersion + "/floatingips/12345");
|
||||
|
||||
/*
|
|
@ -71,7 +71,7 @@ import org.jclouds.openstack.nova.v2_0.compute.loaders.FindSecurityGroupOrCreate
|
|||
import org.jclouds.openstack.nova.v2_0.compute.loaders.LoadFloatingIpsForInstance;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIpForServer;
|
||||
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.regionscoped.FlavorInRegion;
|
||||
|
@ -137,7 +137,7 @@ public class NovaComputeServiceContextModule extends
|
|||
|
||||
bind(TemplateOptions.class).to(NovaTemplateOptions.class);
|
||||
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndId, Iterable<? extends FloatingIP>>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndId, Iterable<? extends FloatingIpForServer>>>() {
|
||||
}).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class);
|
||||
|
||||
bind(new TypeLiteral<Function<RegionSecurityGroupNameAndPorts, SecurityGroup>>() {
|
||||
|
@ -214,8 +214,8 @@ public class NovaComputeServiceContextModule extends
|
|||
@Provides
|
||||
@Singleton
|
||||
@Named("FLOATINGIP")
|
||||
protected final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> instanceToFloatingIps(
|
||||
@Named("FLOATINGIP") CacheLoader<RegionAndId, Iterable<? extends FloatingIP>> in) {
|
||||
protected final LoadingCache<RegionAndId, Iterable<? extends FloatingIpForServer>> instanceToFloatingIps(
|
||||
@Named("FLOATINGIP") CacheLoader<RegionAndId, Iterable<? extends FloatingIpForServer>> in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ public class NovaComputeServiceContextModule extends
|
|||
|
||||
@Override
|
||||
public boolean apply(RegionAndId regionAndId) {
|
||||
checkNotNull(regionAndId, "regionAndId");
|
||||
checkNotNull(regionAndId, "serverId");
|
||||
Server server = api.getServerApi(regionAndId.getRegion()).get(regionAndId.getId());
|
||||
if (server == null) {
|
||||
throw new IllegalStateException(String.format("Server %s not found.", regionAndId.getId()));
|
||||
|
@ -333,7 +333,7 @@ public class NovaComputeServiceContextModule extends
|
|||
|
||||
@Override
|
||||
public boolean apply(RegionAndId regionAndId) {
|
||||
checkNotNull(regionAndId, "regionAndId");
|
||||
checkNotNull(regionAndId, "serverId");
|
||||
Server server = api.getServerApi(regionAndId.getRegion()).get(regionAndId.getId());
|
||||
return server == null;
|
||||
}
|
||||
|
|
|
@ -25,19 +25,29 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jclouds.Context;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.openstack.neutron.v2.NeutronApi;
|
||||
import org.jclouds.openstack.neutron.v2.domain.Network;
|
||||
import org.jclouds.openstack.neutron.v2.domain.Networks;
|
||||
import org.jclouds.openstack.neutron.v2.domain.Port;
|
||||
import org.jclouds.openstack.neutron.v2.features.NetworkApi;
|
||||
import org.jclouds.openstack.neutron.v2.features.PortApi;
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NodeAndNovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIpForServer;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
|
||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||
import org.jclouds.rest.ApiContext;
|
||||
import org.jclouds.rest.InsufficientResourcesException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
|
@ -45,30 +55,38 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A function for adding and allocating an ip to a node
|
||||
*/
|
||||
public class AllocateAndAddFloatingIpToNode implements
|
||||
Function<AtomicReference<NodeAndNovaTemplateOptions>, AtomicReference<NodeMetadata>> {
|
||||
public class AllocateAndAddFloatingIpToNode
|
||||
implements Function<AtomicReference<NodeAndNovaTemplateOptions>, AtomicReference<NodeMetadata>> {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named("openstack-neutron")
|
||||
private Supplier<Context> neutronContextSupplier;
|
||||
|
||||
private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
|
||||
private final NovaApi novaApi;
|
||||
private final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache;
|
||||
private final LoadingCache<RegionAndId, Iterable<? extends FloatingIpForServer>> floatingIpCache;
|
||||
private final CleanupResources cleanupResources;
|
||||
|
||||
@Inject
|
||||
public AllocateAndAddFloatingIpToNode(@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
NovaApi novaApi, @Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache, CleanupResources cleanupResources) {
|
||||
public AllocateAndAddFloatingIpToNode(
|
||||
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning, NovaApi novaApi,
|
||||
@Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIpForServer>> floatingIpCache,
|
||||
CleanupResources cleanupResources) {
|
||||
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
|
||||
this.novaApi = checkNotNull(novaApi, "novaApi");
|
||||
this.floatingIpCache = checkNotNull(floatingIpCache, "floatingIpCache");
|
||||
|
@ -78,13 +96,45 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
@Override
|
||||
public AtomicReference<NodeMetadata> apply(AtomicReference<NodeAndNovaTemplateOptions> input) {
|
||||
checkState(nodeRunning.apply(input.get().getNodeMetadata()), "node never achieved state running %s", input.get().getNodeMetadata());
|
||||
NodeMetadata node = input.get().getNodeMetadata().get();
|
||||
final NodeMetadata node = input.get().getNodeMetadata().get();
|
||||
// node's location is a host
|
||||
String regionId = node.getLocation().getParent().getId();
|
||||
FloatingIPApi floatingIpApi = novaApi.getFloatingIPApi(regionId).get();
|
||||
Optional<Set<String>> poolNames = input.get().getNovaTemplateOptions().get().getFloatingIpPoolNames();
|
||||
|
||||
Optional<FloatingIP> ip = allocateFloatingIPForNode(floatingIpApi, poolNames, node.getId());
|
||||
String availabilityZone = getAvailabilityZoneFromTemplateOptionsOrDefault(input, regionId);
|
||||
|
||||
if (isNeutronLinked()) {
|
||||
org.jclouds.openstack.neutron.v2.features.FloatingIPApi neutronFloatingApi = getFloatingIPApi(regionId);
|
||||
final Optional<Port> optionalPort = getPortApi(regionId).list().concat().firstMatch(new Predicate<Port>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable Port input) {
|
||||
return input.getDeviceId().equals(node.getProviderId());
|
||||
}
|
||||
});
|
||||
if (optionalPort.isPresent()) {
|
||||
Optional<org.jclouds.openstack.neutron.v2.domain.FloatingIP> floatingIPOptional = tryFindExistingFloatingIp(neutronFloatingApi, availabilityZone);
|
||||
org.jclouds.openstack.neutron.v2.domain.FloatingIP floatingIP;
|
||||
if (floatingIPOptional.isPresent()) {
|
||||
floatingIP = floatingIPOptional.get();
|
||||
} else {
|
||||
floatingIP = createFloatingIpUsingNeutron(neutronFloatingApi, node, poolNames, availabilityZone);
|
||||
}
|
||||
|
||||
org.jclouds.openstack.neutron.v2.domain.FloatingIP ip = neutronFloatingApi.update(floatingIP.getId(),
|
||||
org.jclouds.openstack.neutron.v2.domain.FloatingIP.UpdateFloatingIP
|
||||
.updateBuilder()
|
||||
.portId(optionalPort.get().getId())
|
||||
.build());
|
||||
|
||||
input.get().getNodeMetadata().set(NodeMetadataBuilder.fromNodeMetadata(node).publicAddresses(ImmutableSet.of(ip.getFloatingIpAddress())).build());
|
||||
} else {
|
||||
logger.error("Node %s doesn't have a port to attach a floating IP", node);
|
||||
throw new IllegalStateException("Missing required port in node: " + node);
|
||||
}
|
||||
} else { // try nova
|
||||
FloatingIPApi floatingIpApi = novaApi.getFloatingIPApi(regionId).get();
|
||||
|
||||
Optional<FloatingIP> ip = allocateFloatingIPForNodeOnNova(floatingIpApi, poolNames, node.getId());
|
||||
if (!ip.isPresent()) {
|
||||
cleanupResources.apply(node);
|
||||
throw new InsufficientResourcesException("Failed to allocate a FloatingIP for node(" + node.getId() + ")");
|
||||
|
@ -92,23 +142,34 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
logger.debug(">> adding floatingIp(%s) to node(%s)", ip.get().getIp(), node.getId());
|
||||
|
||||
floatingIpApi.addToServer(ip.get().getIp(), node.getProviderId());
|
||||
|
||||
input.get().getNodeMetadata().set(NodeMetadataBuilder.fromNodeMetadata(node).publicAddresses(ImmutableSet.of(ip.get().getIp())).build());
|
||||
floatingIpCache.asMap().putIfAbsent(RegionAndId.fromSlashEncoded(node.getId()), ImmutableList.of(ip.get()));
|
||||
floatingIpCache.asMap().put(RegionAndId.fromSlashEncoded(node.getId()), ImmutableList.of(FloatingIpForServer.create(RegionAndId.fromSlashEncoded(node.getId()), ip.get().getId(), ip.get().getIp())));
|
||||
}
|
||||
return input.get().getNodeMetadata();
|
||||
}
|
||||
|
||||
private String getAvailabilityZoneFromTemplateOptionsOrDefault(AtomicReference<NodeAndNovaTemplateOptions> input, String regionId) {
|
||||
return MoreObjects.firstNonNull(input.get().getNovaTemplateOptions().get().getAvailabilityZone(),
|
||||
Iterables.get(novaApi.getAvailabilityZoneApi(regionId).get().listAvailabilityZones(), 0).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a FloatingIP for a given Node
|
||||
*
|
||||
* @param floatingIpApi FloatingIPApi to create or query for a valid FloatingIP
|
||||
* @param poolNames optional set of pool names from which we will attempt to allocate an IP from. Most cases this is null
|
||||
* @param nodeID optional id of the Node we are trying to allocate a FloatingIP for. Used here only for logging purposes
|
||||
* @param floatingIpApi
|
||||
* FloatingIPApi to create or query for a valid FloatingIP
|
||||
* @param poolNames
|
||||
* optional set of pool names from which we will attempt to allocate
|
||||
* an IP from. Most cases this is null
|
||||
* @param nodeID
|
||||
* optional id of the Node we are trying to allocate a FloatingIP for.
|
||||
* Used here only for logging purposes
|
||||
* @return Optional<FloatingIP>
|
||||
*/
|
||||
private synchronized Optional<FloatingIP> allocateFloatingIPForNode(FloatingIPApi floatingIpApi, Optional<Set<String>> poolNames, String nodeID) {
|
||||
private synchronized Optional<FloatingIP> allocateFloatingIPForNodeOnNova(FloatingIPApi floatingIpApi,
|
||||
Optional<Set<String>> poolNames, String nodeID) {
|
||||
|
||||
FloatingIP ip = null;
|
||||
FloatingIP ip;
|
||||
|
||||
// 1.) Attempt to allocate from optionally passed poolNames
|
||||
if (poolNames.isPresent()) {
|
||||
|
@ -118,9 +179,11 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
ip = floatingIpApi.allocateFromPool(poolName);
|
||||
return Optional.of(ip);
|
||||
} catch (ResourceNotFoundException ex) {
|
||||
logger.trace("<< [%s] failed to allocate floating IP from pool %s for node(%s)", ex.getMessage(), poolName, nodeID);
|
||||
logger.trace("<< [%s] failed to allocate floating IP from pool %s for node(%s)", ex.getMessage(),
|
||||
poolName, nodeID);
|
||||
} catch (InsufficientResourcesException ire) {
|
||||
logger.trace("<< [%s] failed to allocate floating IP from pool %s for node(%s)", ire.getMessage(), poolName, nodeID);
|
||||
logger.trace("<< [%s] failed to allocate floating IP from pool %s for node(%s)", ire.getMessage(),
|
||||
poolName, nodeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,10 +199,11 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
logger.trace("<< [%s] failed to create floating IP for node(%s)", ire.getMessage(), nodeID);
|
||||
}
|
||||
|
||||
// 3.) If no IP was found make final attempt by searching through list of available IP's
|
||||
// 3.) If no IP was found make final attempt by searching through list of
|
||||
// available IP's
|
||||
logger.trace(">> searching for existing, unassigned floating IP for node(%s)", nodeID);
|
||||
List<FloatingIP> unassignedIps = Lists.newArrayList(Iterables.filter(floatingIpApi.list(),
|
||||
new Predicate<FloatingIP>() {
|
||||
List<FloatingIP> unassignedIps = Lists
|
||||
.newArrayList(Iterables.filter(floatingIpApi.list(), new Predicate<FloatingIP>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(FloatingIP arg0) {
|
||||
|
@ -156,8 +220,72 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
return Optional.fromNullable(ip);
|
||||
}
|
||||
|
||||
private Optional<org.jclouds.openstack.neutron.v2.domain.FloatingIP> tryFindExistingFloatingIp(org.jclouds.openstack.neutron.v2.features.FloatingIPApi neutronFloatingApi, final String availabilityZone) {
|
||||
Optional<org.jclouds.openstack.neutron.v2.domain.FloatingIP> floatingIPOptional = neutronFloatingApi.list().concat().firstMatch(new Predicate<org.jclouds.openstack.neutron.v2.domain.FloatingIP>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable org.jclouds.openstack.neutron.v2.domain.FloatingIP input) {
|
||||
return input.getPortId() == null && input.getAvailabilityZone().equals(availabilityZone);
|
||||
}
|
||||
});
|
||||
return floatingIPOptional;
|
||||
}
|
||||
|
||||
private org.jclouds.openstack.neutron.v2.domain.FloatingIP createFloatingIpUsingNeutron(org.jclouds.openstack.neutron.v2.features.FloatingIPApi neutronFloatingApi,
|
||||
NodeMetadata node, Optional<Set<String>> poolNames, final String availabilityZone) {
|
||||
String regionId = node.getLocation().getParent().getId();
|
||||
List<Network> networks = getSuitableNetworks(regionId, availabilityZone, poolNames.or(Sets.<String>newHashSet()));
|
||||
org.jclouds.openstack.neutron.v2.domain.FloatingIP floatingIP = null;
|
||||
for (Network network : networks) {
|
||||
try {
|
||||
logger.debug(">> allocating floating IP from network %s for node(%s)", network, node);
|
||||
org.jclouds.openstack.neutron.v2.domain.FloatingIP createFloatingIP = org.jclouds.openstack.neutron.v2.domain.FloatingIP.CreateFloatingIP.createBuilder(network.getId()).availabilityZone(network.getAvailabilityZone()).build();
|
||||
floatingIP = neutronFloatingApi.create((org.jclouds.openstack.neutron.v2.domain.FloatingIP.CreateFloatingIP) createFloatingIP);
|
||||
logger.debug(">> allocated floating IP(%s) from network(%s) for node(%s)", floatingIP, network, node);
|
||||
floatingIpCache.asMap().put(RegionAndId.fromSlashEncoded(node.getId()), ImmutableList.of(FloatingIpForServer.create(RegionAndId.fromSlashEncoded(node.getId()), floatingIP.getId(), floatingIP.getFloatingIpAddress())));
|
||||
return floatingIP;
|
||||
} catch (Exception ex) {
|
||||
logger.trace("<< [%s] failed to allocate a floating IP from network %s for node(%s)", ex.getMessage(), network, node);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Failed to allocate a floating IP for node " + node + ".\n" +
|
||||
"Failed to find suitable external networks or to allocate from poolNames specified: "
|
||||
+ Iterables.toString(poolNames.get()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all suitable networks to allocate a floating ip
|
||||
*
|
||||
* It will prefer networks specified using the poolNames first and then the external networks in the given availability zone
|
||||
*/
|
||||
private List<Network> getSuitableNetworks(String regionId, final String availabilityZone, final Set<String> poolNames) {
|
||||
List<Network> allNetworks = getNetworkApi(regionId).list().concat().toList();
|
||||
Iterable<Network> externalNetworks = Iterables.filter(allNetworks, Networks.Predicates.externalNetworks(availabilityZone));
|
||||
Iterable<Network> networksFromPoolName = Iterables.filter(allNetworks, Networks.Predicates.namedNetworks(poolNames));
|
||||
return Lists.newArrayList(Iterables.concat(networksFromPoolName, externalNetworks));
|
||||
}
|
||||
|
||||
private boolean isNeutronLinked() {
|
||||
return neutronContextSupplier != null && neutronContextSupplier.get() != null;
|
||||
}
|
||||
|
||||
private org.jclouds.openstack.neutron.v2.features.FloatingIPApi getFloatingIPApi(String region) {
|
||||
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getFloatingIPApi(region);
|
||||
}
|
||||
|
||||
private PortApi getPortApi(String regionId) {
|
||||
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getPortApi(regionId);
|
||||
}
|
||||
|
||||
private NetworkApi getNetworkApi(String regionId) {
|
||||
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getNetworkApi(regionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper("AllocateAndAddFloatingIpToNode").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ public class CleanupResources implements Function<NodeMetadata, Boolean> {
|
|||
|
||||
public boolean removeSecurityGroupCreatedByJcloudsAndInvalidateCache(Set<String> tags) {
|
||||
String securityGroupIdCreatedByJclouds = getSecurityGroupIdCreatedByJclouds(tags);
|
||||
if (securityGroupIdCreatedByJclouds == null) return true;
|
||||
return securityGroupExtension.removeSecurityGroup(securityGroupIdCreatedByJclouds);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,19 +19,23 @@ package org.jclouds.openstack.nova.v2_0.compute.functions;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.Context;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.openstack.neutron.v2.NeutronApi;
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIpForServer;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
|
||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import org.jclouds.rest.ApiContext;
|
||||
|
||||
/**
|
||||
* A function for removing and deallocating an ip address from a node
|
||||
|
@ -42,31 +46,51 @@ public class RemoveFloatingIpFromNodeAndDeallocate implements Function<RegionAnd
|
|||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named("openstack-neutron")
|
||||
private Supplier<Context> neutronContextSupplier;
|
||||
|
||||
private final NovaApi novaApi;
|
||||
private final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache;
|
||||
private final LoadingCache<RegionAndId, Iterable<? extends FloatingIpForServer>> floatingIpCache;
|
||||
|
||||
@Inject
|
||||
public RemoveFloatingIpFromNodeAndDeallocate(NovaApi novaApi,
|
||||
@Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache) {
|
||||
@Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIpForServer>> floatingIpCache) {
|
||||
this.novaApi = checkNotNull(novaApi, "novaApi");
|
||||
this.floatingIpCache = checkNotNull(floatingIpCache, "floatingIpCache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionAndId apply(RegionAndId id) {
|
||||
if (isNeutronLinked()) {
|
||||
for (FloatingIpForServer floatingIpForServer : floatingIpCache.getUnchecked(id)) {
|
||||
logger.debug(">> deallocating floatingIp(%s)", floatingIpForServer);
|
||||
getFloatingIPApi(id.getRegion()).delete(floatingIpForServer.floatingIpId());
|
||||
}
|
||||
} else { // try nova
|
||||
FloatingIPApi floatingIpApi = novaApi.getFloatingIPApi(id.getRegion()).get();
|
||||
for (FloatingIP ip : floatingIpCache.getUnchecked(id)) {
|
||||
logger.debug(">> removing floatingIp(%s) from node(%s)", ip, id);
|
||||
floatingIpApi.removeFromServer(ip.getIp(), id.getId());
|
||||
logger.debug(">> deallocating floatingIp(%s)", ip);
|
||||
floatingIpApi.delete(ip.getId());
|
||||
for (FloatingIpForServer floatingIpForServer : floatingIpCache.getUnchecked(id)) {
|
||||
logger.debug(">> removing floatingIp(%s) from node(%s)", floatingIpForServer, id);
|
||||
floatingIpApi.removeFromServer(floatingIpForServer.ip(), id.getId());
|
||||
logger.debug(">> deallocating floatingIp(%s)", floatingIpForServer);
|
||||
floatingIpApi.delete(floatingIpForServer.floatingIpId());
|
||||
}
|
||||
}
|
||||
floatingIpCache.invalidate(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
// FIXME remove duplications from AllocateAndAddFloatingIpToNode
|
||||
private boolean isNeutronLinked() {
|
||||
return neutronContextSupplier != null && neutronContextSupplier.get() != null;
|
||||
}
|
||||
|
||||
private org.jclouds.openstack.neutron.v2.features.FloatingIPApi getFloatingIPApi(String region) {
|
||||
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getFloatingIPApi(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper("RemoveFloatingIpFromNodeAndDecreate").toString();
|
||||
return MoreObjects.toStringHelper("RemoveFloatingIpFromNodeAndDeallocate").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,10 @@ package org.jclouds.openstack.nova.v2_0.compute.loaders;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIpForServer;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
|
||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||
|
||||
|
@ -35,7 +37,7 @@ import com.google.common.collect.ImmutableSet;
|
|||
* them.
|
||||
*/
|
||||
@Singleton
|
||||
public class LoadFloatingIpsForInstance extends CacheLoader<RegionAndId, Iterable<? extends FloatingIP>> {
|
||||
public class LoadFloatingIpsForInstance extends CacheLoader<RegionAndId, Iterable<? extends FloatingIpForServer>> {
|
||||
private final NovaApi api;
|
||||
|
||||
@Inject
|
||||
|
@ -44,7 +46,7 @@ public class LoadFloatingIpsForInstance extends CacheLoader<RegionAndId, Iterabl
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterable<? extends FloatingIP> load(final RegionAndId key) throws Exception {
|
||||
public Iterable<? extends FloatingIpForServer> load(final RegionAndId key) throws Exception {
|
||||
String region = key.getRegion();
|
||||
Optional<? extends FloatingIPApi> ipApiOptional = api.getFloatingIPApi(region);
|
||||
if (ipApiOptional.isPresent()) {
|
||||
|
@ -54,6 +56,12 @@ public class LoadFloatingIpsForInstance extends CacheLoader<RegionAndId, Iterabl
|
|||
public boolean apply(FloatingIP input) {
|
||||
return key.getId().equals(input.getInstanceId());
|
||||
}
|
||||
})
|
||||
.transform(new Function<FloatingIP, FloatingIpForServer>() {
|
||||
@Override
|
||||
public FloatingIpForServer apply(FloatingIP input) {
|
||||
return FloatingIpForServer.create(key, input.getId(), input.getIp());
|
||||
}
|
||||
});
|
||||
}
|
||||
return ImmutableSet.of();
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.domain;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
|
||||
|
||||
@AutoValue
|
||||
public abstract class FloatingIpForServer {
|
||||
|
||||
public abstract RegionAndId serverId();
|
||||
public abstract String floatingIpId();
|
||||
public abstract String ip();
|
||||
|
||||
public static FloatingIpForServer create(RegionAndId serverId,
|
||||
String floatingIpId,
|
||||
String ip
|
||||
) {
|
||||
return new AutoValue_FloatingIpForServer(serverId, floatingIpId, ip);
|
||||
}
|
||||
|
||||
FloatingIpForServer() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.domain;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jclouds.json.SerializedNames;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@AutoValue
|
||||
public abstract class PortInterface {
|
||||
|
||||
public enum State {
|
||||
PROVISIONING, QUEUED, ACTIVE;
|
||||
|
||||
public static State fromValue(String value) {
|
||||
Optional<State> state = Enums.getIfPresent(State.class, value.toUpperCase());
|
||||
checkArgument(state.isPresent(), "Expected one of %s but was %s", Joiner.on(',').join(State.values()), value);
|
||||
return state.get();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String portId();
|
||||
public abstract String netId();
|
||||
public abstract State portState();
|
||||
public abstract List<FixedIP> fixedIPS();
|
||||
|
||||
@SerializedNames({"port_id", "net_id", "port_state", "fixed_ips"})
|
||||
public static PortInterface create(String portId, String netId, State portState, List<FixedIP> fixedIPS) {
|
||||
return new AutoValue_PortInterface(portId, netId, portState,
|
||||
fixedIPS == null ? ImmutableList.<FixedIP> of() : ImmutableList.copyOf(fixedIPS)
|
||||
);
|
||||
}
|
||||
|
||||
PortInterface() {}
|
||||
|
||||
}
|
|
@ -42,6 +42,7 @@ import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
|||
import org.jclouds.collect.PagedIterable;
|
||||
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.PortInterface;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
|
||||
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
|
||||
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
|
||||
|
@ -446,4 +447,18 @@ public interface ServerApi {
|
|||
@Fallback(Fallbacks.EmptySetOnNotFoundOr404.class)
|
||||
Set<SecurityGroup> listSecurityGroupForServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* Lists port interfaces that are attached to a server.
|
||||
*
|
||||
* @param id
|
||||
* id of the server
|
||||
* @return a list of ports attached to the server
|
||||
*/
|
||||
@Named("server:getPortInterfaces")
|
||||
@GET
|
||||
@Path("/{id}/os-interface")
|
||||
@SelectJson("interfaceAttachments")
|
||||
@Fallback(Fallbacks.EmptySetOnNotFoundOr404.class)
|
||||
Set<PortInterface> listPortInterfaces(@PathParam("id") String id);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,15 +21,12 @@ import static java.util.logging.Logger.getAnonymousLogger;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
|
||||
import org.jclouds.logging.config.LoggingModule;
|
||||
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||
import org.jclouds.openstack.keystone.config.KeystoneProperties;
|
||||
import org.jclouds.openstack.nova.v2_0.config.NovaProperties;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Module;
|
||||
|
||||
@Test(groups = "live", singleThreaded = true, testName = "NovaComputeServiceLiveTest")
|
||||
|
@ -44,16 +41,6 @@ public class NovaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
|||
return new SshjSshClientModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggingModule getLoggingModule() {
|
||||
return new SLF4JLoggingModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Module> setupModules() {
|
||||
return ImmutableSet.of(getLoggingModule(), credentialStoreModule, getSshModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testOptionToNotBlock() {
|
||||
// start call is blocking anyway.
|
||||
|
@ -62,14 +49,12 @@ public class NovaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
|||
@Test(enabled = true, dependsOnMethods = "testReboot")
|
||||
public void testSuspendResume() throws Exception {
|
||||
try {
|
||||
// may fail because of lack of AdminActions extension or non-admin user, so log
|
||||
// and continue
|
||||
// may fail because of lack of AdminActions extension or non-admin user, so log and continue
|
||||
super.testSuspendResume();
|
||||
} catch (AuthorizationException e) {
|
||||
getAnonymousLogger().info("testSuspendResume() threw, probably due to lack of privileges: " + e.getMessage());
|
||||
} catch (UnsupportedOperationException e) {
|
||||
getAnonymousLogger().info(
|
||||
"testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
|
||||
getAnonymousLogger().info("testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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.compute;
|
||||
|
||||
import static java.util.logging.Logger.getAnonymousLogger;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.jclouds.Context;
|
||||
import org.jclouds.ContextBuilder;
|
||||
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
|
||||
import org.jclouds.config.ContextLinking;
|
||||
import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
|
||||
import org.jclouds.logging.config.LoggingModule;
|
||||
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||
import org.jclouds.openstack.keystone.config.KeystoneProperties;
|
||||
import org.jclouds.openstack.nova.v2_0.config.NovaProperties;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Module;
|
||||
|
||||
@Test(groups = "live", singleThreaded = true, testName = "NovaWithNeutronComputeServiceLiveTest")
|
||||
public class NovaWithNeutronComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
||||
|
||||
private Context neutronApiContext;
|
||||
|
||||
public NovaWithNeutronComputeServiceLiveTest() {
|
||||
provider = "openstack-nova";
|
||||
|
||||
Properties overrides = setupProperties();
|
||||
neutronApiContext = ContextBuilder.newBuilder("openstack-neutron")
|
||||
.endpoint(setIfTestSystemPropertyPresent(overrides,
|
||||
"openstack-nova.endpoint"))
|
||||
.credentials(setIfTestSystemPropertyPresent(overrides,
|
||||
"openstack-nova.identity"),
|
||||
setIfTestSystemPropertyPresent(overrides, "openstack-nova.credential"))
|
||||
.modules(ImmutableSet.<Module>of(
|
||||
new SshjSshClientModule(),
|
||||
new SLF4JLoggingModule(),
|
||||
new BouncyCastleCryptoModule())
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Module getSshModule() {
|
||||
return new SshjSshClientModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggingModule getLoggingModule() {
|
||||
return new SLF4JLoggingModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Module> setupModules() {
|
||||
return ImmutableSet.of(
|
||||
ContextLinking.linkContext(neutronApiContext),
|
||||
getLoggingModule(),
|
||||
credentialStoreModule,
|
||||
getSshModule()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testOptionToNotBlock() {
|
||||
// start call is blocking anyway.
|
||||
}
|
||||
|
||||
@Test(enabled = true, dependsOnMethods = "testReboot")
|
||||
public void testSuspendResume() throws Exception {
|
||||
try {
|
||||
// may fail because of lack of AdminActions extension or non-admin user, so log and continue
|
||||
super.testSuspendResume();
|
||||
} catch (AuthorizationException e) {
|
||||
getAnonymousLogger().info("testSuspendResume() threw, probably due to lack of privileges: " + e.getMessage());
|
||||
} catch (UnsupportedOperationException e) {
|
||||
getAnonymousLogger().info("testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true, dependsOnMethods = "testSuspendResume")
|
||||
@Override
|
||||
public void testGetNodesWithDetails() throws Exception {
|
||||
super.testGetNodesWithDetails();
|
||||
}
|
||||
|
||||
@Test(enabled = true, dependsOnMethods = "testSuspendResume")
|
||||
@Override
|
||||
public void testListNodes() throws Exception {
|
||||
super.testListNodes();
|
||||
}
|
||||
|
||||
@Test(enabled = true, dependsOnMethods = "testSuspendResume")
|
||||
@Override
|
||||
public void testListNodesByIds() throws Exception {
|
||||
super.testListNodesByIds();
|
||||
}
|
||||
|
||||
@Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails", "testListNodesByIds" })
|
||||
@Override
|
||||
public void testDestroyNodes() {
|
||||
super.testDestroyNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties setupProperties() {
|
||||
Properties props = super.setupProperties();
|
||||
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
|
||||
setIfTestSystemPropertyPresent(props, NovaProperties.AUTO_ALLOCATE_FLOATING_IPS);
|
||||
return props;
|
||||
}
|
||||
}
|
|
@ -68,13 +68,26 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(200).payload(
|
||||
payloadFromResource("/floatingip_details.json")).build();
|
||||
|
||||
HttpRequest listAZs = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-availability-zone")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
|
||||
.put("X-Auth-Token", authToken)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
HttpResponse listAZsResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
|
||||
payloadFromResource("/availability_zone_list.json")).build();
|
||||
|
||||
HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.3");
|
||||
|
||||
AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
|
||||
createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse).build()).getContext().utils().injector()
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
|
||||
.put(listAZs, listAZsResponseForUnassigned)
|
||||
.put(extensionsOfNovaRequest, extensionsOfNovaResponse)
|
||||
.put(createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse).build())
|
||||
.getContext().utils().injector()
|
||||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
|
@ -110,6 +123,16 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
"{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot create any more addresses\", \"code\": 400}}",
|
||||
"application/json")).build();
|
||||
|
||||
HttpRequest listAZs = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-availability-zone")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
|
||||
.put("X-Auth-Token", authToken)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
HttpResponse listAZsResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
|
||||
payloadFromResource("/availability_zone_list.json")).build();
|
||||
|
||||
HttpRequest list = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-floating-ips")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
|
||||
|
@ -121,11 +144,15 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.5");
|
||||
|
||||
AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
|
||||
createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse).put(list,
|
||||
listResponseForUnassigned).build()).getContext().utils().injector()
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
|
||||
.put(listAZs, listAZsResponseForUnassigned)
|
||||
.put(extensionsOfNovaRequest, extensionsOfNovaResponse)
|
||||
.put(createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse)
|
||||
.put(list, listResponseForUnassigned)
|
||||
.build())
|
||||
.getContext().utils().injector()
|
||||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
|
@ -148,6 +175,16 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
"{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot create any more addresses\", \"code\": 404}}",
|
||||
"application/json")).build();
|
||||
|
||||
HttpRequest listAZs = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-availability-zone")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
|
||||
.put("X-Auth-Token", authToken)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
HttpResponse listAZsResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
|
||||
payloadFromResource("/availability_zone_list.json")).build();
|
||||
|
||||
HttpRequest list = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-floating-ips")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
|
||||
|
@ -159,11 +196,14 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.5");
|
||||
|
||||
AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
|
||||
createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse).put(list,
|
||||
listResponseForUnassigned).build()).getContext().utils().injector()
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
|
||||
.put(listAZs, listAZsResponseForUnassigned)
|
||||
.put(extensionsOfNovaRequest, extensionsOfNovaResponse)
|
||||
.put(createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse)
|
||||
.put(list, listResponseForUnassigned).build())
|
||||
.getContext().utils().injector()
|
||||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertFalse;
|
|||
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIpForServer;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
|
||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||
import org.testng.annotations.Test;
|
||||
|
@ -50,8 +51,8 @@ public class LoadFloatingIpsForInstanceTest {
|
|||
replay(ipApi);
|
||||
|
||||
LoadFloatingIpsForInstance parser = new LoadFloatingIpsForInstance(api);
|
||||
|
||||
assertEquals(ImmutableSet.copyOf(parser.load(RegionAndId.fromRegionAndId("RegionOne", "i-blah"))), ImmutableSet.of(testIp));
|
||||
FloatingIpForServer floatingIpForServer = FloatingIpForServer.create(RegionAndId.fromRegionAndId("RegionOne", "i-blah"), "1", "1.1.1.1");
|
||||
assertEquals(ImmutableSet.copyOf(parser.load(RegionAndId.fromRegionAndId("RegionOne", "i-blah"))), ImmutableSet.of(floatingIpForServer));
|
||||
|
||||
verify(api);
|
||||
verify(ipApi);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"availabilityZoneInfo": [
|
||||
{
|
||||
"zoneState": {
|
||||
"available": true
|
||||
},
|
||||
"hosts": null,
|
||||
"zoneName": "uk-1a"
|
||||
},
|
||||
{
|
||||
"zoneState": {
|
||||
"available": true
|
||||
},
|
||||
"hosts": null,
|
||||
"zoneName": "uk-1b"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -270,7 +270,6 @@ public abstract class Aws4SignerBase {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hash string (encoding UTF_8) with sha256
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue