From 5d82a3df97723453e1b7dc90bfd8e248be160fdd Mon Sep 17 00:00:00 2001 From: Nelson Araujo Date: Mon, 13 Nov 2017 13:40:18 -0800 Subject: [PATCH] JCLOUDS-1355: Enable VM creation without external IP address. --- .../GoogleComputeEngineServiceAdapter.java | 23 +++++--- .../GoogleComputeEngineTemplateOptions.java | 19 ++++++- .../domain/NewInstance.java | 14 +++-- .../GoogleComputeEngineServiceMockTest.java | 52 +++++++++++++++++++ .../test/resources/instance_insert_no_ip.json | 42 +++++++++++++++ 5 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 providers/google-compute-engine/src/test/resources/instance_insert_no_ip.json diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java index 523c1b058f..c5b31273a9 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java @@ -19,7 +19,6 @@ package org.jclouds.googlecomputeengine.compute; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Lists.newArrayList; import static java.lang.String.format; import static org.jclouds.googlecloud.internal.ListPages.concat; import static org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName.fromRegionAndName; @@ -52,10 +51,12 @@ import org.jclouds.googlecomputeengine.domain.AttachDisk; import org.jclouds.googlecomputeengine.domain.DiskType; import org.jclouds.googlecomputeengine.domain.Image; import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig; import org.jclouds.googlecomputeengine.domain.Instance.Scheduling; import org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance; import org.jclouds.googlecomputeengine.domain.MachineType; import org.jclouds.googlecomputeengine.domain.NewInstance; +import org.jclouds.googlecomputeengine.domain.NewInstance.NetworkInterface; import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Region; import org.jclouds.googlecomputeengine.domain.Subnetwork; @@ -148,16 +149,24 @@ public final class GoogleComputeEngineServiceAdapter Scheduling scheduling = getScheduling(options); - NewInstance newInstance = new NewInstance.Builder(name, + List networks = Lists.newArrayList(); + if (options.assignExternalIp()) { + networks.add(NetworkInterface.create(network, subnetwork)); + } else { + // Do not assign an externally facing IP address to the machine. + networks.add(NetworkInterface.create(network, subnetwork, ImmutableList.of())); + } + + NewInstance.Builder newInstanceBuilder = new NewInstance.Builder(name, template.getHardware().getUri(), // machineType - network, - subnetwork, + networks, disks) .description(group) .tags(Tags.create(null, ImmutableList.copyOf(options.getTags()))) .serviceAccounts(options.serviceAccounts()) - .scheduling(scheduling) - .build(); + .scheduling(scheduling); + + NewInstance newInstance = newInstanceBuilder.build(); // Add metadata from template and for ssh key and image id newInstance.metadata().putAll(options.getUserMetadata()); @@ -216,7 +225,7 @@ public final class GoogleComputeEngineServiceAdapter } @Override public Iterable listImages() { - List> images = newArrayList(); + List> images = Lists.newArrayList(); images.add(concat(api.images().list())); diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java index 288a35f3a6..dc78d362f9 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java @@ -28,6 +28,7 @@ import org.jclouds.scriptbuilder.domain.Statement; /** Instance options specific to Google Compute Engine. */ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { + private boolean assignExternalIp = true; private boolean autoCreateKeyPair = true; private boolean autoCreateWindowsPassword; private List serviceAccounts; @@ -46,6 +47,7 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { super.copyTo(to); if (to instanceof GoogleComputeEngineTemplateOptions) { GoogleComputeEngineTemplateOptions eTo = GoogleComputeEngineTemplateOptions.class.cast(to); + eTo.assignExternalIp(assignExternalIp()); eTo.autoCreateKeyPair(autoCreateKeyPair()); eTo.serviceAccounts(serviceAccounts()); eTo.autoCreateWindowsPassword(autoCreateWindowsPassword()); @@ -69,6 +71,21 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { return bootDiskType; } + /** + * Sets whether an external IP address should be assigned to the machine. + */ + public GoogleComputeEngineTemplateOptions assignExternalIp(boolean assignExternalIp) { + this.assignExternalIp = assignExternalIp; + return this; + } + + /** + * Gets whether an external IP address should be assigned to the machine. + */ + public boolean assignExternalIp() { + return assignExternalIp; + } + /** * Sets whether an SSH key pair should be created automatically. */ @@ -115,7 +132,7 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { * the password if and only if the image is for a Windows VM. */ public Boolean autoCreateWindowsPassword() { - return autoCreateWindowsPassword; + return autoCreateWindowsPassword; } /** diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java index 67d9925a26..43f38fbfac 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java @@ -37,19 +37,19 @@ import com.google.common.collect.ImmutableList; @AutoValue public abstract class NewInstance { @AutoValue - abstract static class NetworkInterface { + public abstract static class NetworkInterface { abstract URI network(); @Nullable abstract URI subnetwork(); abstract List accessConfigs(); - static NetworkInterface create(URI network, URI subnetwork) { + public static NetworkInterface create(URI network, URI subnetwork) { return create(network, subnetwork, Arrays.asList(AccessConfig.create(null, Type.ONE_TO_ONE_NAT, null))); } @SerializedNames({ "network", "subnetwork", "accessConfigs" }) - static NetworkInterface create(URI network, URI subnetwork, List accessConfigs) { + public static NetworkInterface create(URI network, URI subnetwork, List accessConfigs) { return new AutoValue_NewInstance_NetworkInterface(network, subnetwork, accessConfigs); } @@ -131,6 +131,14 @@ public abstract class NewInstance { this.disks = disks; } + public Builder(String name, URI machineType, List networks, List disks) { + checkNotNull(name, "NewInstance name cannot be null"); + this.name = name; + this.machineType = machineType; + this.networkInterfaces = ImmutableList.copyOf(networks); + this.disks = disks; + } + public Builder(String name, URI machineType, URI network, URI subnetwork, URI sourceImage) { checkNotNull(name, "NewInstance name cannot be null"); this.name = name; diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java index e5216e52da..a81b17522a 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java @@ -319,6 +319,58 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1"); } + public void createNodeWithoutExternalIp() throws Exception { + server.enqueue(singleRegionSingleZoneResponse()); + server.enqueue(jsonResponse("/image_list.json")); + server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud" + server.enqueue(jsonResponse("/aggregated_machinetype_list.json")); + server.enqueue(jsonResponse("/subnetwork_get.json")); + server.enqueue(jsonResponse("/network_get.json")); + server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall + server.enqueue(jsonResponse("/operation.json")); // Create Firewall + server.enqueue(jsonResponse("/zone_operation.json")); + server.enqueue(aggregatedListWithInstanceNetworkAndStatus("test-0", "test-network", RUNNING)); + server.enqueue(jsonResponse("/disk_get_with_source_image.json")); + server.enqueue(jsonResponse("/image_get_for_source_image.json")); + server.enqueue(jsonResponse("/disktype_ssd.json")); + server.enqueue(jsonResponse("/operation.json")); // Create Instance + server.enqueue(instanceWithNetworkAndStatusAndSsd("test-1", "test-network", RUNNING)); + + ComputeService computeService = computeService(); + + GoogleComputeEngineTemplateOptions options = computeService.templateOptions() + .as(GoogleComputeEngineTemplateOptions.class).autoCreateKeyPair(false) + .tags(ImmutableSet.of("aTag")).blockUntilRunning(false) + .bootDiskType("pd-ssd").networks("jclouds-test").assignExternalIp(false); + + Template template = computeService.templateBuilder().options(options).build(); + NodeMetadata node = getOnlyElement(computeService.createNodesInGroup("test", 1, template)); + + // prove our caching works. + assertEquals(node.getImageId(), template.getImage().getId()); + assertEquals(node.getLocation().getId(), template.getLocation().getId()); + + assertSent(server, "GET", "/projects/party/regions"); + assertSent(server, "GET", "/projects/party/global/images"); + assertSent(server, "GET", "/projects/debian-cloud/global/images"); + assertSent(server, "GET", "/projects/party/aggregated/machineTypes"); + assertSent(server, "GET", "/projects/party/regions/us-central1/subnetworks/jclouds-test"); + assertSent(server, "GET", "/projects/party/global/networks/mynetwork"); + assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall + assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall + stringFromResource("/firewall_insert_3.json")); + + assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060"); + assertSent(server, "GET", "/projects/party/aggregated/instances"); + assertSent(server, "GET", "/projects/party/zones/us-central1-a/disks/test"); + assertSent(server, "GET", "/projects/debian-cloud/global/images/debian-7-wheezy-v20140718"); + assertSent(server, "GET", "/projects/party/zones/us-central1-a/diskTypes/pd-ssd"); + assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances", + String.format(stringFromResource("/instance_insert_no_ip.json"), template.getHardware().getId(), template.getImage().getId())); + + assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1"); + } + private MockResponse instanceWithNetworkAndStatus(String instanceName, String networkName, Instance.Status status) { return new MockResponse().setBody( stringFromResource("/instance_get.json").replace("test-0", instanceName).replace("default", networkName) diff --git a/providers/google-compute-engine/src/test/resources/instance_insert_no_ip.json b/providers/google-compute-engine/src/test/resources/instance_insert_no_ip.json new file mode 100644 index 0000000000..ce8b9a2e2f --- /dev/null +++ b/providers/google-compute-engine/src/test/resources/instance_insert_no_ip.json @@ -0,0 +1,42 @@ +{ + "machineType": "%s", + "name": "test-1", + "networkInterfaces": [ + { + "network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork", + "subnetwork": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion/subnetworks/jclouds-test", + "accessConfigs": [] + } + ], + "disks": [ + { + "type": "PERSISTENT", + "initializeParams": { + "sourceImage": "%s", + "diskType": "https://content.googleapis.com/compute/v1/projects/party/zones/us-central1-a/diskTypes/pd-ssd" + }, + "boot": true, + "autoDelete": true + } + ], + "description": "test", + "tags": { + "items": [ + "aTag", + "jclouds-test-65f" + ] + }, + "metadata": { + "items": [ + { + "key": "jclouds-group", + "value": "test" + } + ] + }, + "scheduling": { + "onHostMaintenance": "MIGRATE", + "automaticRestart": true, + "preemptible": false + } +} \ No newline at end of file