diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java index 0241c171e1..e4ceade1bc 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java @@ -110,7 +110,12 @@ public class NovaComputeServiceAdapter implements options.userData(templateOptions.getUserData()); options.diskConfig(templateOptions.getDiskConfig()); options.configDrive(templateOptions.getConfigDrive()); - options.networks(templateOptions.getNetworks()); + if (templateOptions.getNovaNetworks() != null) { + options.novaNetworks(templateOptions.getNovaNetworks()); + } + if (templateOptions.getNetworks() != null) { + options.networks(templateOptions.getNetworks()); + } Optional privateKey = Optional.absent(); if (templateOptions.getKeyPairName() != null) { diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java index d82d90163e..24328b8eee 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java @@ -27,6 +27,8 @@ import java.util.Set; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.LoginCredentials; +import org.jclouds.openstack.nova.v2_0.domain.Network; +import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions; import org.jclouds.scriptbuilder.domain.Statement; import com.google.common.base.Objects; @@ -76,6 +78,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { } eTo.configDrive(getConfigDrive()); + eTo.novaNetworks(getNovaNetworks()); } } @@ -86,6 +89,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { protected byte[] userData; protected String diskConfig; protected boolean configDrive; + protected Set novaNetworks; @Override public boolean equals(Object o) { @@ -100,12 +104,13 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { && equal(this.keyPairName, that.keyPairName) && Arrays.equals(this.userData, that.userData) && equal(this.diskConfig, that.diskConfig) - && equal(this.configDrive, that.configDrive); + && equal(this.configDrive, that.configDrive) + && equal(this.novaNetworks, that.novaNetworks); } @Override public int hashCode() { - return Objects.hashCode(super.hashCode(), autoAssignFloatingIp, securityGroupNames, generateKeyPair, keyPairName, userData, diskConfig, configDrive); + return Objects.hashCode(super.hashCode(), autoAssignFloatingIp, securityGroupNames, generateKeyPair, keyPairName, userData, diskConfig, configDrive, novaNetworks); } @Override @@ -121,6 +126,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { toString.add("userData", userData); toString.add("diskConfig", diskConfig); toString.add("configDrive", configDrive); + toString.add("novaNetworks", novaNetworks); return toString; } @@ -228,6 +234,13 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { return configDrive; } + /** + * @see CreateServerOptions#getNetworks() + */ + public Set getNovaNetworks() { + return novaNetworks; + } + public static class Builder { /** @@ -396,6 +409,14 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { NovaTemplateOptions options = new NovaTemplateOptions(); return NovaTemplateOptions.class.cast(options.configDrive(configDrive)); } + + /** + * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getNetworks() + */ + public static NovaTemplateOptions novaNetworks(Set novaNetworks) { + NovaTemplateOptions options = new NovaTemplateOptions(); + return NovaTemplateOptions.class.cast(options.novaNetworks(novaNetworks)); + } } // methods that only facilitate returning the correct object type @@ -537,13 +558,23 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { } /** - * {@inheritDoc} + *
Ensures NovaTemplateOptions can work with networks specified as Strings. + * Also provides for compatibility with the abstraction layer. */ @Override public NovaTemplateOptions networks(Iterable networks) { return NovaTemplateOptions.class.cast(super.networks(networks)); } + /** + *
Ensures NovaTemplateOptions can work with networks specified as Strings. + * Also provides for compatibility with the abstraction layer. + */ + @Override + public NovaTemplateOptions networks(String... networks) { + return NovaTemplateOptions.class.cast(super.networks(networks)); + } + /** * User data as bytes (not base64-encoded) */ @@ -575,4 +606,15 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable { this.configDrive = configDrive; return this; } + + /** + * @param novaNetworks The list of network declarations. + * Nova-specific network declarations allow for specifying network UUIDs, port UUIDs, and fixed IPs. + * Unline {@link #networks(Iterable)} this supports setting additional network parameters and not just network UUIDs. + * @see CreateServerOptions#getNetworks() + */ + public NovaTemplateOptions novaNetworks(Set novaNetworks) { + this.novaNetworks = novaNetworks; + return this; + } } diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Network.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Network.java new file mode 100644 index 0000000000..516f6e1b0c --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Network.java @@ -0,0 +1,173 @@ +/* + * 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 java.beans.ConstructorProperties; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Nova (or Neutron) network definition + * Used to provide support for network, port, and fixed_ip when booting Nova servers. + * OpenStack will support either a Nova Network or Neutron, but not both at the same time. + * Specifying a port is only possible with Neutron. + * @author Zack Shoylev + */ +public class Network implements Comparable { + private final String networkUuid; + private final String portUuid; + private final String fixedIp; + + @ConstructorProperties({ + "networkUuid", "portUuid", "fixedIp" + }) + protected Network(String networkUuid, String portUuid, String fixedIp) { + checkArgument(networkUuid != null || portUuid != null, "At least one of networkUuid or portUuid should be specified"); + this.networkUuid = networkUuid; + this.portUuid = portUuid; + this.fixedIp = fixedIp; + } + + /** + * @return the network uuid - Neutron or Nova + */ + public String getNetworkUuid() { + return this.networkUuid; + } + + /** + * @return the port uuid - Neutron only + */ + public String getPortUuid() { + return this.portUuid; + } + + /** + * @return the fixed IP address - Neutron or Nova + */ + public String getFixedIp() { + return this.fixedIp; + } + + @Override + public int hashCode() { + return Objects.hashCode(networkUuid, portUuid, fixedIp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Network that = Network.class.cast(obj); + return Objects.equal(this.networkUuid, that.networkUuid) && + Objects.equal(this.portUuid, that.portUuid) && + Objects.equal(this.fixedIp, that.fixedIp); + } + + protected ToStringHelper string() { + return Objects.toStringHelper(this) + .add("networkUuid", networkUuid) + .add("portUuid", portUuid) + .add("fixedIp", fixedIp); + } + + @Override + public String toString() { + return string().toString(); + } + + /** + * @return A new builder object + */ + public static Builder builder() { + return new Builder(); + } + + /** + * @return A new Builder object from another Network + */ + public Builder toBuilder() { + return new Builder().fromNetwork(this); + } + + /** + * Implements the Builder pattern for this class + */ + public static class Builder { + protected String networkUuid; + protected String portUuid; + protected String fixedIp; + + /** + * @param networkUuid The UUID for the Nova network or Neutron subnet to be attached. + * @return The builder object. + * @see Network#getNetworkUuid() + */ + public Builder networkUuid(String networkUuid) { + this.networkUuid = networkUuid; + return this; + } + + /** + * @param portUuid The port UUID for this Neutron Network. + * @return The builder object. + * @see Network#getPortUuid() + */ + public Builder portUuid(String portUuid) { + this.portUuid = portUuid; + return this; + } + + /** + * @param fixedIp The fixed IP address for this Network (if any). + * Service automatically assigns IP address if this is not provided. + * Fixed IP is compatible with both Nova Network and Neutron. + * @return The builder object. + * @see Network#getFixedIp() + */ + public Builder fixedIp(String fixedIp) { + this.fixedIp = fixedIp; + return this; + } + + /** + * @return A new Network object. + */ + public Network build() { + return new Network(networkUuid, portUuid, fixedIp); + } + + /** + * @param in The target Network + * @return A Builder from the provided Network + */ + public Builder fromNetwork(Network in) { + return this + .networkUuid(in.getNetworkUuid()) + .portUuid(in.getPortUuid()) + .fixedIp(in.getFixedIp()); + } + } + + @Override + public int compareTo(Network that) { + return this.toString().compareTo(that.toString()); + } +} 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 57aadcc7a7..1e3147e7fa 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 @@ -16,24 +16,6 @@ */ package org.jclouds.openstack.nova.v2_0.options; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.collect.ForwardingObject; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import org.jclouds.http.HttpRequest; -import org.jclouds.rest.MapBinder; -import org.jclouds.rest.binders.BindToJsonPayload; - -import javax.inject.Inject; -import javax.inject.Named; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - import static com.google.common.base.Objects.equal; import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; @@ -42,9 +24,34 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Strings.emptyToNull; import static com.google.common.io.BaseEncoding.base64; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.http.HttpRequest; +import org.jclouds.openstack.nova.v2_0.NovaApi; +import org.jclouds.openstack.nova.v2_0.domain.Network; +import org.jclouds.openstack.nova.v2_0.domain.Server; +import org.jclouds.rest.MapBinder; +import org.jclouds.rest.binders.BindToJsonPayload; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Optional; +import com.google.common.collect.ForwardingObject; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + /** * @author Adrian Cole * @author Inbar Stolberg + * @author Zack Shoylev */ public class CreateServerOptions implements MapBinder { @Inject @@ -106,6 +113,7 @@ public class CreateServerOptions implements MapBinder { private byte[] userData; private String diskConfig; private Set networks = ImmutableSet.of(); + private Set novaNetworks = ImmutableSet.of(); private String availabilityZone; private boolean configDrive; @@ -216,8 +224,22 @@ public class CreateServerOptions implements MapBinder { server.diskConfig = diskConfig; } - if (!networks.isEmpty()) { + if (!networks.isEmpty() || !novaNetworks.isEmpty()) { server.networks = Sets.newLinkedHashSet(); // ensures ordering is preserved - helps testing and more intuitive for users. + for (Network network : novaNetworks) { + // Avoid serializing null values, which are common here. + ImmutableMap.Builder networkMap = new ImmutableMap.Builder(); + if(network.getNetworkUuid() != null) { + networkMap.put("uuid", network.getNetworkUuid()); + } + if(network.getPortUuid() != null) { + networkMap.put("port", network.getPortUuid()); + } + if(network.getFixedIp() != null) { + networkMap.put("fixed_ip", network.getFixedIp()); + } + server.networks.add(networkMap.build()); + } for (String network : networks) { server.networks.add(ImmutableMap.of("uuid", network)); } @@ -364,6 +386,16 @@ public class CreateServerOptions implements MapBinder { public Set getNetworks() { return networks; } + + /** + * Get custom networks specified for the server. + * + * @return A set of uuids defined by Neutron (previously Quantum) + * @see Neutron Networks + */ + public Set getNovaNetworks() { + return novaNetworks; + } /** * @see #getSecurityGroupNames @@ -406,22 +438,37 @@ public class CreateServerOptions implements MapBinder { } /** - * @see #getNetworks + * Determines if a configuration drive will be attached to the server or not. + * This can be used for cloud-init or other configuration purposes. */ - public CreateServerOptions networks(String... networks) { - return networks(ImmutableSet.copyOf(networks)); + public boolean getConfigDrive() { + return configDrive; } /** * @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; } + /** + * @see #getNetworks + * Overwrites networks supplied by {@link #networks(Iterable)} + */ + public CreateServerOptions novaNetworks(Iterable networks) { + this.novaNetworks = ImmutableSet.copyOf(networks); + return this; + } + + /** + * @see #getNetworks + */ + public CreateServerOptions networks(String... networks) { + return networks(ImmutableSet.copyOf(networks)); + } + public static class Builder { /** @@ -493,6 +540,14 @@ public class CreateServerOptions implements MapBinder { return CreateServerOptions.class.cast(options.networks(networks)); } + /** + * @see CreateServerOptions#getNetworks + */ + public static CreateServerOptions novaNetworks(Iterable networks) { + CreateServerOptions options = new CreateServerOptions(); + return CreateServerOptions.class.cast(options.novaNetworks(networks)); + } + /** * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getAvailabilityZone() */ diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java index 52190cb731..a9dce036e3 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java @@ -32,6 +32,7 @@ import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v2_0.domain.KeyPair; +import org.jclouds.openstack.nova.v2_0.domain.Network; import org.jclouds.openstack.nova.v2_0.domain.Server; import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ServerInZone; import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName; @@ -40,6 +41,7 @@ import org.testng.annotations.Test; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.TypeLiteral; @@ -165,6 +167,53 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC assertNotNull(server); } + public void testCreateNodeWithGroupEncodedIntoNameWithNovaNetworks() 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\":\"12345\", \"port\":\"67890\", \"fixed_ip\":\"192.168.0.1\"},{\"uuid\":\"54321\", \"port\":\"09876\", \"fixed_ip\":\"192.168.0.2\"},{\"uuid\":\"non-nova-uuid\"}]}}","application/json")) + .build(); + + HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted") + .payload(payloadFromResourceWithContentType("/new_server_nova_networks.json","application/json; charset=UTF-8")).build(); + + Map requestResponseMap = ImmutableMap. builder() + .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess) + .put(extensionsOfNovaRequest, extensionsOfNovaResponse) + .put(listDetail, listDetailResponse) + .put(listFlavorsDetail, listFlavorsDetailResponse) + .put(createServer, createServerResponse) + .put(serverDetail, serverDetailResponse).build(); + + Injector forNovaNetworks = requestsSendResponses(requestResponseMap); + + Template template = forNovaNetworks.getInstance(TemplateBuilder.class).build(); + template.getOptions().as(NovaTemplateOptions.class) + .networks("non-nova-uuid") + .novaNetworks( + ImmutableSet.of( + Network.builder() + .networkUuid("12345") + .portUuid("67890") + .fixedIp("192.168.0.1") + .build(), + Network.builder() + .networkUuid("54321") + .portUuid("09876") + .fixedIp("192.168.0.2") + .build())); + + NovaComputeServiceAdapter adapter = forNovaNetworks.getInstance(NovaComputeServiceAdapter.class); + + NodeAndInitialCredentials server = adapter.createNodeWithGroupEncodedIntoName("test", "test-e92", template); + assertNotNull(server); + } + public void testCreateNodeWithGroupEncodedIntoNameWhenSecurityGroupsArePresent() throws Exception { HttpRequest createServer = HttpRequest diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java index 7f8ea9c1c7..3553d1888b 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java @@ -21,6 +21,7 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import org.jclouds.openstack.nova.v2_0.domain.Network; import org.jclouds.openstack.nova.v2_0.domain.Server; import org.jclouds.openstack.nova.v2_0.domain.ServerCreated; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; @@ -31,6 +32,7 @@ import org.jclouds.openstack.v2_0.domain.Resource; import org.jclouds.openstack.v2_0.predicates.LinkPredicates; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; /** @@ -42,133 +44,163 @@ import com.google.common.collect.Iterables; @Test(groups = "live", testName = "ServerApiLiveTest") public class ServerApiLiveTest extends BaseNovaApiLiveTest { - @Test(description = "GET /v${apiVersion}/{tenantId}/servers") - public void testListServers() throws Exception { - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - for (Resource server : serverApi.list().concat()) { - checkResource(server); - } - } - } + @Test(description = "GET /v${apiVersion}/{tenantId}/servers") + public void testListServers() throws Exception { + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + for (Resource server : serverApi.list().concat()) { + checkResource(server); + } + } + } - @Test(description = "GET /v${apiVersion}/{tenantId}/servers/detail") - public void testListServersInDetail() throws Exception { - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - for (Server server : serverApi.listInDetail().concat()) { - checkServer(server); - } - } - } + @Test(description = "GET /v${apiVersion}/{tenantId}/servers/detail") + public void testListServersInDetail() throws Exception { + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + for (Server server : serverApi.listInDetail().concat()) { + checkServer(server); + } + } + } - @Test(description = "GET /v${apiVersion}/{tenantId}/servers/{id}", dependsOnMethods = { "testListServersInDetail" }) - public void testGetServerById() throws Exception { - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - for (Resource server : serverApi.list().concat()) { - Server details = serverApi.get(server.getId()); - assertEquals(details.getId(), server.getId()); - assertEquals(details.getName(), server.getName()); - assertEquals(details.getLinks(), server.getLinks()); - checkServer(details); - } - } - } + @Test(description = "GET /v${apiVersion}/{tenantId}/servers/{id}", dependsOnMethods = { "testListServersInDetail" }) + public void testGetServerById() throws Exception { + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + for (Resource server : serverApi.list().concat()) { + Server details = serverApi.get(server.getId()); + assertEquals(details.getId(), server.getId()); + assertEquals(details.getName(), server.getName()); + assertEquals(details.getLinks(), server.getLinks()); + checkServer(details); + } + } + } - @Test - public void testCreateInAvailabilityZone() { - String serverId = null; - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - try { - serverId = createServer(zoneId, "nova", Server.Status.ACTIVE).getId(); - Server server = serverApi.get(serverId); - assertEquals(server.getStatus(), Server.Status.ACTIVE); - } finally { - serverApi.delete(serverId); + @Test + public void testCreateInAvailabilityZone() { + String serverId = null; + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + try { + serverId = createServer(zoneId, "nova", Server.Status.ACTIVE).getId(); + Server server = serverApi.get(serverId); + assertEquals(server.getStatus(), Server.Status.ACTIVE); + } finally { + serverApi.delete(serverId); + } + } + } + + /** + * This needs to be supported by the provider, and is usually not supported. + * However this can be tested on devstack: + * In apis/openstack-nova: + * mvn -Plive clean install "-Dtest.openstack-nova.endpoint=http://localhost:5000/v2.0" "-Dtest.openstack-nova.identity=demo:demo" "-Dtest.openstack-nova.credential=devstack" "-Dtest=org.jclouds.openstack.nova.v2_0.features.ServerApiLiveTest#testCreateWithNetworkOptions" + */ + @Test(enabled = false) + public void testCreateWithNetworkOptions() { + String serverId = null; + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + try { + CreateServerOptions options = CreateServerOptions.Builder.novaNetworks( + // This network UUID must match an existing network. + ImmutableSet.of(Network.builder().networkUuid("bc4cfa2b-2b27-4671-8e8f-73009623def0").fixedIp("192.168.55.56").build()) + ); + ServerCreated server = serverApi.create(hostName, imageIdForZone(zoneId), "1", options); + serverId = server.getId(); + + blockUntilServerInState(server.getId(), serverApi, Server.Status.ACTIVE); + Server serverCheck = serverApi.get(serverId); + assertEquals(serverCheck.getStatus(), Server.Status.ACTIVE); + } finally { + if (serverId != null) { + serverApi.delete(serverId); } - } - } + } + } + } - @Test - public void testCreateInWrongAvailabilityZone() { - String serverId = null; - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - try { - serverId = createServer(zoneId, "err", Server.Status.ERROR).getId(); - Server server = serverApi.get(serverId); - assertEquals(server.getStatus(), Server.Status.ERROR); - } finally { - serverApi.delete(serverId); - } - } - } + @Test + public void testCreateInWrongAvailabilityZone() { + String serverId = null; + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + try { + serverId = createServer(zoneId, "err", Server.Status.ERROR).getId(); + Server server = serverApi.get(serverId); + assertEquals(server.getStatus(), Server.Status.ERROR); + } finally { + serverApi.delete(serverId); + } + } + } - @Test - public void testRebuildServer() { + @Test + public void testRebuildServer() { - String serverId = null; + String serverId = null; - for (String zoneId : zones) { - ServerApi serverApi = api.getServerApiForZone(zoneId); - try { - serverId = createServer(zoneId, Server.Status.ACTIVE).getId(); + for (String zoneId : zones) { + ServerApi serverApi = api.getServerApiForZone(zoneId); + try { + serverId = createServer(zoneId, Server.Status.ACTIVE).getId(); - Server server = serverApi.get(serverId); + Server server = serverApi.get(serverId); - assertEquals(server.getStatus(), Server.Status.ACTIVE); + assertEquals(server.getStatus(), Server.Status.ACTIVE); - RebuildServerOptions options = new RebuildServerOptions(). - withImage(server.getImage().getId()). - name("newName"). - adminPass("password"). - ipv4Address("1.1.1.1"). - ipv6Address("fe80::100"); + RebuildServerOptions options = new RebuildServerOptions(). + withImage(server.getImage().getId()). + name("newName"). + adminPass("password"). + ipv4Address("1.1.1.1"). + ipv6Address("fe80::100"); - serverApi.rebuild(serverId, options); + serverApi.rebuild(serverId, options); - Server rebuiltServer = serverApi.get(serverId); + Server rebuiltServer = serverApi.get(serverId); - assertEquals("newName", rebuiltServer.getName()); - assertEquals("1.1.1.1", rebuiltServer.getAccessIPv4()); - assertEquals("fe80::100", rebuiltServer.getAccessIPv6()); + assertEquals("newName", rebuiltServer.getName()); + assertEquals("1.1.1.1", rebuiltServer.getAccessIPv4()); + assertEquals("fe80::100", rebuiltServer.getAccessIPv6()); - } finally { - serverApi.delete(serverId); - } - } - } + } finally { + serverApi.delete(serverId); + } + } + } - private Server createServer(String regionId, Server.Status serverStatus) { - ServerApi serverApi = api.getServerApiForZone(regionId); - CreateServerOptions options = new CreateServerOptions(); - ServerCreated server = serverApi.create(hostName, imageIdForZone(regionId), flavorRefForZone(regionId), options); + private Server createServer(String regionId, Server.Status serverStatus) { + ServerApi serverApi = api.getServerApiForZone(regionId); + CreateServerOptions options = new CreateServerOptions(); + ServerCreated server = serverApi.create(hostName, imageIdForZone(regionId), flavorRefForZone(regionId), options); - blockUntilServerInState(server.getId(), serverApi, serverStatus); + blockUntilServerInState(server.getId(), serverApi, serverStatus); - return serverApi.get(server.getId()); - } + return serverApi.get(server.getId()); + } - private Server createServer(String regionId, String availabilityZoneId, Server.Status serverStatus) { - ServerApi serverApi = api.getServerApiForZone(regionId); - CreateServerOptions options = new CreateServerOptions(); - options = options.availabilityZone(availabilityZoneId); - ServerCreated server = serverApi.create(hostName, imageIdForZone(regionId), flavorRefForZone(regionId), options); - blockUntilServerInState(server.getId(), serverApi, serverStatus); - return serverApi.get(server.getId()); - } + private Server createServer(String regionId, String availabilityZoneId, Server.Status serverStatus) { + ServerApi serverApi = api.getServerApiForZone(regionId); + CreateServerOptions options = new CreateServerOptions(); + options = options.availabilityZone(availabilityZoneId); + ServerCreated server = serverApi.create(hostName, imageIdForZone(regionId), flavorRefForZone(regionId), options); + blockUntilServerInState(server.getId(), serverApi, serverStatus); + return serverApi.get(server.getId()); + } - private void checkResource(Resource resource) { - assertNotNull(resource.getId()); - assertNotNull(resource.getName()); - assertNotNull(resource.getLinks()); - assertTrue(Iterables.any(resource.getLinks(), LinkPredicates.relationEquals(Relation.SELF))); - } + private void checkResource(Resource resource) { + assertNotNull(resource.getId()); + assertNotNull(resource.getName()); + assertNotNull(resource.getLinks()); + assertTrue(Iterables.any(resource.getLinks(), LinkPredicates.relationEquals(Relation.SELF))); + } - private void checkServer(Server server) { - checkResource(server); - assertFalse(server.getAddresses().isEmpty()); - } + private void checkServer(Server server) { + checkResource(server); + assertFalse(server.getAddresses().isEmpty()); + } } diff --git a/apis/openstack-nova/src/test/resources/new_server_nova_networks.json b/apis/openstack-nova/src/test/resources/new_server_nova_networks.json new file mode 100644 index 0000000000..d0f4322aa6 --- /dev/null +++ b/apis/openstack-nova/src/test/resources/new_server_nova_networks.json @@ -0,0 +1,41 @@ +{ + "server": { + "status": "BUILD(scheduling)", + "updated": "2012-03-19T06:21:13Z", + "hostId": "", + "user_id": "54297837463082", + "name": "test-e92", + "links": [{ + "href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/71752", + "rel": "self" + }, { + "href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/71752", + "rel": "bookmark" + }], + "addresses": {}, + "tenant_id": "37936628937291", + "image": { + "id": "1241", + "links": [{ + "href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1241", + "rel": "bookmark" + }] + }, + "created": "2012-03-19T06:21:13Z", + "uuid": "47491020-6a78-4f63-9475-23195ac4515c", + "accessIPv4": "", + "accessIPv6": "", + "key_name": null, + "adminPass": "ZWuHcmTMQ7eXoHeM", + "flavor": { + "id": "100", + "links": [{ + "href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100", + "rel": "bookmark" + }] + }, + "id": 71752, + "metadata": {}, + "OS-DCF:diskConfig": "AUTO" + } +}