JCLOUDS-906: Add ServiceAccounts to GoogleComputeEngineTemplateOptions

This commit is contained in:
Daniel Broudy 2015-05-29 10:13:31 -07:00 committed by Ignasi Barrera
parent aa33619c92
commit 55348c0ddb
7 changed files with 219 additions and 24 deletions

View File

@ -138,15 +138,14 @@ public final class GoogleComputeEngineServiceAdapter
tags.add(naming.name(ports));
}
NewInstance newInstance = NewInstance.create(
name, // name
NewInstance newInstance = new NewInstance.Builder( name,
template.getHardware().getUri(), // machineType
network, // network
disks, // disks
group, // description
Tags.create(null, ImmutableList.copyOf(tags)) // tags
);
network,
disks)
.description(group)
.tags(Tags.create(null, ImmutableList.copyOf(tags)))
.serviceAccounts(options.serviceAccounts())
.build();
// Add metadata from template and for ssh key and image id
newInstance.metadata().putAll(options.getUserMetadata());
@ -177,7 +176,7 @@ public final class GoogleComputeEngineServiceAdapter
null, // networkInterfaces
null, // disks
newInstance.metadata(), // metadata
null, // serviceAccounts
newInstance.serviceAccounts(), // serviceAccounts
Scheduling.create(OnHostMaintenance.MIGRATE, true) // scheduling
));
checkState(instanceVisible.apply(instance), "instance %s is not api visible!", instance.get());

View File

@ -16,16 +16,19 @@
*/
package org.jclouds.googlecomputeengine.compute.options;
import java.util.List;
import java.util.Map;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
/** Instance options specific to Google Compute Engine. */
public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
private boolean autoCreateKeyPair = true;
private List<ServiceAccount> serviceAccounts;
@Override
public GoogleComputeEngineTemplateOptions clone() {
@ -40,6 +43,7 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
if (to instanceof GoogleComputeEngineTemplateOptions) {
GoogleComputeEngineTemplateOptions eTo = GoogleComputeEngineTemplateOptions.class.cast(to);
eTo.autoCreateKeyPair(autoCreateKeyPair());
eTo.serviceAccounts(serviceAccounts());
}
}
@ -52,12 +56,30 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
}
/**
* Sets whether an SSH key pair should be created automatically.
* Gets whether an SSH key pair should be created automatically.
*/
public boolean autoCreateKeyPair() {
return autoCreateKeyPair;
}
/**
* Sets a list of service accounts, with their specified scopes, to authorize on created instance.
* For example, to give a node the 'compute' scope you would add a service account with the email 'default'
* and the scope 'https://www.googleapis.com/auth/compute'
* These scopes will be given to all nodes created with these template options.
*/
public GoogleComputeEngineTemplateOptions serviceAccounts(List<ServiceAccount> serviceAccounts){
this.serviceAccounts = serviceAccounts;
return this;
}
/**
* Gets the list of service accounts, with their specified scopes, that will be authorize on created instances.
*/
public List<ServiceAccount> serviceAccounts(){
return serviceAccounts;
}
/**
* {@inheritDoc}
*/

View File

@ -17,6 +17,7 @@
package org.jclouds.googlecomputeengine.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Arrays;
@ -80,7 +81,8 @@ public abstract class NewInstance {
return create(name, machineType, network, Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null, null);
}
public static NewInstance create(String name, URI machineType, URI network, List<AttachDisk> disks, @Nullable String description, @Nullable Tags tags) {
public static NewInstance create(String name, URI machineType, URI network, List<AttachDisk> disks,
@Nullable String description, @Nullable Tags tags) {
checkArgument(disks.get(0).boot(), "disk 0 must be a boot disk! %s", disks);
boolean foundBoot = false;
for (AttachDisk disk : disks) {
@ -93,13 +95,86 @@ public abstract class NewInstance {
description, tags != null ? tags : Tags.create(), Metadata.create(), null, null);
}
@SerializedNames({ "name", "machineType", "canIpForward", "networkInterfaces", "disks", "description", "tags", "metadata",
"serviceAccounts", "scheduling" })
static NewInstance create(String name, URI machineType, Boolean canIpForward, List<NetworkInterface> networkInterfaces,
List<AttachDisk> disks, String description, Tags tags, Metadata metadata, List<ServiceAccount> serviceAccounts, Scheduling scheduling) {
return new AutoValue_NewInstance(name, machineType, canIpForward, networkInterfaces, disks, description, tags, metadata, serviceAccounts, scheduling);
@SerializedNames({ "name", "machineType", "canIpForward", "networkInterfaces", "disks", "description",
"tags", "metadata", "serviceAccounts", "scheduling" })
static NewInstance create(String name, URI machineType, Boolean canIpForward,
List<NetworkInterface> networkInterfaces, List<AttachDisk> disks, String description,
Tags tags, Metadata metadata, List<ServiceAccount> serviceAccounts, Scheduling scheduling) {
return new AutoValue_NewInstance(name, machineType, canIpForward, networkInterfaces, disks, description,
tags, metadata, serviceAccounts, scheduling);
}
NewInstance() {
}
public static class Builder {
private String name;
private URI machineType;
private Boolean canIpForward;
private List<NetworkInterface> networkInterfaces;
private List<AttachDisk> disks;
private String description;
private Tags tags;
private Metadata metadata;
private List<ServiceAccount> serviceAccounts;
private Scheduling scheduling;
public Builder(String name, URI machineType, URI network, List<AttachDisk> disks) {
checkNotNull(name, "NewInstance name cannot be null");
this.name = name;
this.machineType = machineType;
this.networkInterfaces = ImmutableList.of(NetworkInterface.create(network));
this.disks = disks;
}
public Builder(String name, URI machineType, URI network, URI sourceImage) {
checkNotNull(name, "NewInstance name cannot be null");
this.name = name;
this.machineType = machineType;
this.networkInterfaces = ImmutableList.of(NetworkInterface.create(network));
this.disks = Arrays.asList(AttachDisk.newBootDisk(sourceImage));
}
public Builder canIpForward(Boolean canIpForward){
this.canIpForward = canIpForward;
return this;
}
public Builder description(String description){
this.description = description;
return this;
}
public Builder tags(Tags tags){
this.tags = tags;
return this;
}
public Builder metadata(Metadata metadata){
this.metadata = metadata;
return this;
}
/**
* A list of service accounts, with their specified scopes, authorized for this instance.
* Service accounts generate access tokens that can be accessed through the metadata server
* and used to authenticate applications on the instance.
* Note: to add scopes to the default service account on the VM you can use 'default' as
* a keyword for email.
*/
public Builder serviceAccounts(List<ServiceAccount> serviceAccounts){
this.serviceAccounts = serviceAccounts;
return this;
}
public Builder scheduling(Scheduling scheduling){
this.scheduling = scheduling;
return this;
}
public NewInstance build() {
return create(name, machineType, canIpForward, networkInterfaces, disks, description, tags != null ? tags : Tags.create(),
metadata != null ? metadata : Metadata.create(), serviceAccounts, scheduling);
}
}
}

View File

@ -40,10 +40,6 @@ public abstract class Tags implements Cloneable {
return Tags.create(null, null);
}
public static Tags create(String fingerprint) {
return Tags.create(fingerprint, null);
}
@SerializedNames({ "fingerprint", "items" })
public static Tags create(String fingerprint, ImmutableList<String> items) { // Dictates the type when created from json!
ImmutableList<String> empty = ImmutableList.of();

View File

@ -34,7 +34,9 @@ import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance;
import org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
import org.jclouds.googlecomputeengine.domain.Metadata;
import org.jclouds.googlecomputeengine.domain.NewInstance;
@ -99,11 +101,16 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
);
instance.metadata().put("mykey", "myvalue");
instance2 = NewInstance.create(
INSTANCE_NAME2, // name
instance2 = new NewInstance.Builder(INSTANCE_NAME2, // name
getDefaultMachineTypeUrl(), // machineType
getNetworkUrl(INSTANCE_NETWORK_NAME), // network
imageUri); // sourceImage
imageUri) // sourceImage
.canIpForward(true)
.description("description")
.tags(Tags.create(null, ImmutableList.of("tag1")))
.serviceAccounts(ImmutableList.of(ServiceAccount.create("default", ImmutableList.of("https://www.googleapis.com/auth/compute"))))
.scheduling(Scheduling.create(OnHostMaintenance.MIGRATE, true))
.build();
return api;
}
@ -116,6 +123,18 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
return api.disksInZone(DEFAULT_ZONE_NAME);
}
@Test(groups = "live", dependsOnMethods = "testInsertInstance")
public void testGetInstance2() {
Instance instance = api().get(INSTANCE_NAME2);
assertNotNull(instance);
assertInstanceEquals(instance, this.instance2);
assertTrue(instance.canIpForward());
assertEquals(instance.description(), "description");
assertEquals(instance.serviceAccounts().get(0).scopes(), ImmutableList.of("https://www.googleapis.com/auth/compute"));
assertTrue(instance.scheduling().automaticRestart());
assertEquals(instance.scheduling().onHostMaintenance(), OnHostMaintenance.MIGRATE);
}
@Test(groups = "live")
public void testInsertInstance() {
// need to insert the network first
@ -294,7 +313,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
assertOperationDoneSuccessfully(api().reset(INSTANCE_NAME));
}
@Test(groups = "live", dependsOnMethods = "testInsertInstance")
@Test(groups = "live", dependsOnMethods = "testGetInstance2")
public void testStopInstance() {
Instance originalInstance = api().get(INSTANCE_NAME2);
assertEquals(originalInstance.status(), Instance.Status.RUNNING);

View File

@ -27,6 +27,8 @@ import org.jclouds.googlecomputeengine.domain.AttachDisk;
import org.jclouds.googlecomputeengine.domain.AttachDisk.DiskInterface;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
import org.jclouds.googlecomputeengine.domain.Metadata;
import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance;
@ -250,6 +252,41 @@ public class InstanceApiMockTest extends BaseGoogleComputeEngineApiMockTest {
assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances/test-1/stop");
}
public void builderTest() throws Exception {
server.enqueue(jsonResponse("/zone_operation.json"));
NewInstance newInstance = new NewInstance.Builder("test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network
URI.create(url("/projects/party/global/images/centos-6-2-v20120326"))).build(); // sourceImage)
assertEquals(instanceApi().create(newInstance), new ParseZoneOperationTest().expected(url("/projects")));
assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances",
stringFromResource("/instance_insert_simple.json"));
}
public void insert_builder_allOptions() throws Exception {
server.enqueue(jsonResponse("/zone_operation.json"));
NewInstance newInstance = new NewInstance.Builder(
"test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network
Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))))
.canIpForward(true)
.description("desc")
.tags(null)
.metadata(Metadata.create().put("aKey", "aValue"))
.serviceAccounts(ImmutableList.of(ServiceAccount.create("default",
ImmutableList.of("https://www.googleapis.com/auth/compute"))))
.scheduling(Scheduling.create(OnHostMaintenance.MIGRATE, true))
.build();
assertEquals(instanceApi().create(newInstance), new ParseZoneOperationTest().expected(url("/projects")));
assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances",
stringFromResource("/instance_insert_full.json"));
}
InstanceApi instanceApi(){
return api().instancesInZone("us-central1-a");
}

View File

@ -0,0 +1,47 @@
{
"name": "test-1",
"machineType": "https://www.googleapis.com/compute/v1/projects/party/zones/us-central1-a/machineTypes/n1-standard-1",
"canIpForward": true,
"networkInterfaces": [
{
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/default",
"accessConfigs": [
{
"type": "ONE_TO_ONE_NAT"
}
]
}
],
"disks": [
{
"type": "PERSISTENT",
"source": "https://www.googleapis.com/compute/v1/projects/party/zones/us-central1-a/disks/test",
"boot": true,
"autoDelete": false
}
],
"description": "desc",
"tags": {
"items": []
},
"metadata": {
"items": [
{
"key": "aKey",
"value": "aValue"
}
]
},
"serviceAccounts": [
{
"email": "default",
"scopes": [
"https://www.googleapis.com/auth/compute"
]
}
],
"scheduling": {
"onHostMaintenance": "MIGRATE",
"automaticRestart": true
}
}