Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
JCLOUDS-934. Add support for specifying boot disk type in compute ser…
Browse files Browse the repository at this point in the history
…vice
  • Loading branch information
abayer committed Jun 15, 2015
1 parent c1b1cfb commit f3555cb
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 20 deletions.
Expand Up @@ -22,19 +22,26 @@
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.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.simplifyPorts;
import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;

import javax.inject.Inject;
import javax.inject.Named;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import javax.inject.Inject;
import javax.inject.Named;

import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Atomics;
import com.google.common.util.concurrent.UncheckedTimeoutException;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.NodeMetadata;
Expand All @@ -49,6 +56,7 @@
import org.jclouds.googlecomputeengine.compute.functions.Resources;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
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.Scheduling;
Expand All @@ -62,15 +70,6 @@
import org.jclouds.googlecomputeengine.features.InstanceApi;
import org.jclouds.location.suppliers.all.JustProvider;

import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Atomics;
import com.google.common.util.concurrent.UncheckedTimeoutException;

/**
* This implementation maps the following:
* <ul>
Expand Down Expand Up @@ -120,8 +119,10 @@ public final class GoogleComputeEngineServiceAdapter
checkNotNull(template.getHardware().getUri(), "hardware must have a URI");
checkNotNull(template.getImage().getUri(), "image URI is null");

String zone = template.getLocation().getId();

List<AttachDisk> disks = Lists.newArrayList();
disks.add(AttachDisk.newBootDisk(template.getImage().getUri()));
disks.add(AttachDisk.newBootDisk(template.getImage().getUri(), getDiskTypeArgument(options, zone)));

Iterator<String> networks = options.getNetworks().iterator();

Expand Down Expand Up @@ -156,7 +157,6 @@ public final class GoogleComputeEngineServiceAdapter
format("%s:%s %s@localhost", credentials.getUser(), options.getPublicKey(), credentials.getUser()));
}

String zone = template.getLocation().getId();
InstanceApi instanceApi = api.instancesInZone(zone);
Operation create = instanceApi.create(newInstance);

Expand Down Expand Up @@ -303,4 +303,15 @@ private static String toName(URI link) {
String path = link.getPath();
return path.substring(path.lastIndexOf('/') + 1);
}

private URI getDiskTypeArgument(GoogleComputeEngineTemplateOptions options, String zone) {
if (options.bootDiskType() != null) {
DiskType diskType = api.diskTypesInZone(zone).get(options.bootDiskType());
if (diskType != null) {
return diskType.selfLink();
}
}

return null;
}
}
Expand Up @@ -21,14 +21,15 @@

import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
import org.jclouds.scriptbuilder.domain.Statement;

/** Instance options specific to Google Compute Engine. */
public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {

private boolean autoCreateKeyPair = true;
private List<ServiceAccount> serviceAccounts;
private String bootDiskType;

@Override
public GoogleComputeEngineTemplateOptions clone() {
Expand All @@ -44,9 +45,25 @@ public void copyTo(TemplateOptions to) {
GoogleComputeEngineTemplateOptions eTo = GoogleComputeEngineTemplateOptions.class.cast(to);
eTo.autoCreateKeyPair(autoCreateKeyPair());
eTo.serviceAccounts(serviceAccounts());
eTo.bootDiskType(bootDiskType());
}
}

/**
* Sets the boot disk type.
*/
public GoogleComputeEngineTemplateOptions bootDiskType(String diskType) {
this.bootDiskType = diskType;
return this;
}

/**
* Gets the boot disk type.
*/
public String bootDiskType() {
return bootDiskType;
}

/**
* Sets whether an SSH key pair should be created automatically.
*/
Expand Down
Expand Up @@ -43,6 +43,10 @@ static InitializeParams create(URI sourceImage) {
return create(null, null, sourceImage, null);
}

static InitializeParams create(URI sourceImage, URI diskType) {
return create(null, null, sourceImage, diskType);
}

@SerializedNames({ "diskName", "diskSizeGb", "sourceImage", "diskType" })
public static InitializeParams create(String diskName, Long diskSizeGb, URI sourceImage, URI diskType) {
return new AutoValue_AttachDisk_InitializeParams(diskName, diskSizeGb, sourceImage, diskType);
Expand Down Expand Up @@ -103,6 +107,10 @@ public static AttachDisk newBootDisk(URI sourceImage) {
return create(Type.PERSISTENT, null, InitializeParams.create(sourceImage), true, true);
}

public static AttachDisk newBootDisk(URI sourceImage, URI diskType) {
return create(Type.PERSISTENT, null, InitializeParams.create(sourceImage, diskType), true, true);
}

public static AttachDisk existingDisk(URI existingDisk) {
return create(Type.PERSISTENT, existingDisk, null, false, false);
}
Expand Down
Expand Up @@ -18,27 +18,34 @@

import static com.google.common.collect.Iterables.contains;
import static org.jclouds.util.Strings2.toStringAndClose;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

import java.net.URI;
import java.util.Properties;
import java.util.Set;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Module;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.googlecloud.internal.TestProperties;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.domain.Disk;
import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.MachineType;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;

@Test(groups = "live", singleThreaded = true)
public class GoogleComputeEngineServiceLiveTest extends BaseComputeServiceLiveTest {

Expand Down Expand Up @@ -67,6 +74,29 @@ public void testListHardwareProfiles() throws Exception {
}
}

public void testCreateNodeWithSsd() throws Exception {
String group = this.group + "ssd";
try {
TemplateOptions options = client.templateOptions();

options.as(GoogleComputeEngineTemplateOptions.class).bootDiskType("pd-ssd");

// create a node
Set<? extends NodeMetadata> nodes =
client.createNodesInGroup(group, 1, options);
assertEquals(nodes.size(), 1, "One node should have been created");

// Verify the disk on the instance is an ssd.
NodeMetadata node = Iterables.get(nodes, 0);
GoogleComputeEngineApi api = client.getContext().unwrapApi(GoogleComputeEngineApi.class);
Instance instance = api.instancesInZone(node.getLocation().getId()).get(node.getName());
Disk disk = api.disksInZone(node.getLocation().getId()).get(toName(instance.disks().get(0).source()));
assertTrue(disk.type().toString().endsWith("pd-ssd"));

} finally {
client.destroyNodesMatching(NodePredicates.inGroup(group));
}
}
/**
* Nodes may have additional metadata entries (particularly they may have an "sshKeys" entry)
*/
Expand Down Expand Up @@ -110,4 +140,10 @@ protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet<String> tag
assert nodeTags.contains(tag) : String.format("node tags did not match %s %s node:", tags, nodeTags, node);
}
}

private static String toName(URI link) {
String path = link.getPath();
return path.substring(path.lastIndexOf('/') + 1);
}

}
Expand Up @@ -184,12 +184,64 @@ public void createNodeWhenFirewallDoesNotExist() throws Exception {
assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1");
}

public void createNodeWithSpecificDiskType() 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("/network_get_default.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("/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");

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/global/networks/default");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall
stringFromResource("/firewall_insert_2.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/diskTypes/pd-ssd");
assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances",
String.format(stringFromResource("/instance_insert_ssd.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)
.replace("RUNNING", status.toString()));
}

private MockResponse instanceWithNetworkAndStatusAndSsd(String instanceName, String networkName, Instance.Status status) {
return new MockResponse().setBody(
stringFromResource("/instance_get.json").replace("test-0", instanceName).replace("default", networkName)
.replace("RUNNING", status.toString()).replace("pd-standard", "pd-ssd"));
}

private MockResponse aggregatedListWithInstanceNetworkAndStatus(String instanceName, String networkName,
Instance.Status status) {
return new MockResponse().setBody(
Expand Down
@@ -0,0 +1,11 @@
{
"kind": "compute#diskType",
"creationTimestamp": "2014-06-02T11:07:28.529-07:00",
"name": "pd-ssd",
"description": "SSD Persistent Disk",
"validDiskSize": "10GB-1TB",
"zone": "https://content.googleapis.com/compute/v1/projects/party/zones/us-central1-a",
"selfLink": "https://content.googleapis.com/compute/v1/projects/party/zones/us-central1-a/diskTypes/pd-ssd",
"defaultDiskSizeGb": "100"
}

@@ -0,0 +1,40 @@
{
"machineType": "%s",
"name": "test-1",
"networkInterfaces": [
{
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/default",
"accessConfigs": [
{
"type": "ONE_TO_ONE_NAT"
}
]
}
],
"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"
}
]
}
}

0 comments on commit f3555cb

Please sign in to comment.