diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java index 3ce1fb345f..c6d42201c2 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java @@ -111,6 +111,7 @@ public class CreateServerOptions implements MapBinder { private List personality = Lists.newArrayList(); private byte[] userData; private String diskConfig; + private Set networks = ImmutableSet.of(); @Override public boolean equals(Object object) { @@ -121,7 +122,8 @@ public class CreateServerOptions implements MapBinder { final CreateServerOptions other = CreateServerOptions.class.cast(object); return equal(keyName, other.keyName) && equal(securityGroupNames, other.securityGroupNames) && equal(metadata, other.metadata) && equal(personality, other.personality) - && equal(adminPass, other.adminPass) && equal(diskConfig, other.diskConfig); + && equal(adminPass, other.adminPass) && equal(diskConfig, other.diskConfig) + && equal(adminPass, other.adminPass) && equal(networks, other.networks); } else { return false; } @@ -129,7 +131,7 @@ public class CreateServerOptions implements MapBinder { @Override public int hashCode() { - return Objects.hashCode(keyName, securityGroupNames, metadata, personality, adminPass); + return Objects.hashCode(keyName, securityGroupNames, metadata, personality, adminPass, networks); } protected ToStringHelper string() { @@ -146,6 +148,8 @@ public class CreateServerOptions implements MapBinder { if (diskConfig != null) toString.add("diskConfig", diskConfig); toString.add("userData", userData == null ? null : new String(userData)); + if (!networks.isEmpty()) + toString.add("networks", networks); return toString; } @@ -167,6 +171,7 @@ public class CreateServerOptions implements MapBinder { String user_data; @Named("OS-DCF:diskConfig") String diskConfig; + Set> networks; private ServerRequest(String name, String imageRef, String flavorRef) { this.name = name; @@ -198,10 +203,18 @@ public class CreateServerOptions implements MapBinder { if (adminPass != null) { server.adminPass = adminPass; } + if (diskConfig != null) { server.diskConfig = diskConfig; } + if (!networks.isEmpty()) { + server.networks = Sets.newLinkedHashSet(); // ensures ordering is preserved - helps testing and more intuitive for users. + for (String network : networks) { + server.networks.add(ImmutableMap.of("uuid", network)); + } + } + return bindToRequest(request, ImmutableMap.of("server", server)); } @@ -218,7 +231,6 @@ public class CreateServerOptions implements MapBinder { } } - /** * You may further customize a cloud server by injecting data into the file * system of the cloud server itself. This is useful, for example, for @@ -314,6 +326,17 @@ public class CreateServerOptions implements MapBinder { /** * + * Get custom networks specified for the server. + * @return A set of uuids defined by Neutron (previously Quantum) + * @see Neutron Networks + * + */ + public Set getNetworks() { + return networks; + } + + /** + * * @see #getSecurityGroupNames */ public CreateServerOptions securityGroupNames(String... securityGroupNames) { @@ -353,6 +376,24 @@ public class CreateServerOptions implements MapBinder { return this; } + /** + * + * @see #getNetworks + */ + public CreateServerOptions networks(String... networks) { + return networks(ImmutableSet.copyOf(networks)); + } + + /** + * @see #getNetworks + */ + public CreateServerOptions networks(Iterable networks) { + for (String network : checkNotNull(networks, "networks")) + checkNotNull(emptyToNull(network), "all networks must be non-empty"); + this.networks = ImmutableSet.copyOf(networks); + return this; + } + public static class Builder { /** @@ -407,6 +448,22 @@ public class CreateServerOptions implements MapBinder { CreateServerOptions options = new CreateServerOptions(); return CreateServerOptions.class.cast(options.diskConfig(diskConfig)); } + + /** + * @see CreateServerOptions#getNetworks + */ + public static CreateServerOptions networks(String... networks) { + CreateServerOptions options = new CreateServerOptions(); + return CreateServerOptions.class.cast(options.networks(networks)); + } + + /** + * @see CreateServerOptions#getNetworks + */ + public static CreateServerOptions networks(Iterable networks) { + CreateServerOptions options = new CreateServerOptions(); + return CreateServerOptions.class.cast(options.networks(networks)); + } } @Override diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java index b6c0011e91..95f6865ea6 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java @@ -128,6 +128,31 @@ public class ServerApiExpectTest extends BaseNovaApiExpectTest { new ParseCreatedServerTest().expected().toString()); } + public void testCreateServerWithNetworksWhenResponseIs202() throws Exception { + + HttpRequest createServer = HttpRequest + .builder() + .method("POST") + .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers") + .addHeader("Accept", "application/json") + .addHeader("X-Auth-Token", authToken) + .payload(payloadFromStringWithContentType( + "{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"networks\":[{\"uuid\":\"b3856ac0-f481-11e2-b778-0800200c9a66\"},{\"uuid\":\"bf0f0f90-f481-11e2-b778-0800200c9a66\"}]}}","application/json")) + .build(); + + + HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted") + .payload(payloadFromResourceWithContentType("/new_server.json","application/json; charset=UTF-8")).build(); + + + NovaApi apiWithNewServer = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, + responseWithKeystoneAccess, createServer, createServerResponse); + + assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").create("test-e92", "1241", + "100", new CreateServerOptions().networks("b3856ac0-f481-11e2-b778-0800200c9a66", "bf0f0f90-f481-11e2-b778-0800200c9a66")).toString(), + new ParseCreatedServerTest().expected().toString()); + } + public void testCreateServerWithDiskConfigAuto() throws Exception { HttpRequest createServer = HttpRequest