JCLOUDS-1355: Enable VM creation without external IP address.

This commit is contained in:
Nelson Araujo 2017-11-13 13:40:18 -08:00 committed by Ignasi Barrera
parent 73c3b6024c
commit 5d82a3df97
5 changed files with 139 additions and 11 deletions

View File

@ -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<NetworkInterface> 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.<AccessConfig>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<Image> listImages() {
List<Iterable<Image>> images = newArrayList();
List<Iterable<Image>> images = Lists.newArrayList();
images.add(concat(api.images().list()));

View File

@ -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<ServiceAccount> 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.
*/

View File

@ -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<AccessConfig> 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<AccessConfig> accessConfigs) {
public static NetworkInterface create(URI network, URI subnetwork, List<AccessConfig> 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<NetworkInterface> networks, List<AttachDisk> 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;

View File

@ -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)

View File

@ -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
}
}