From d3dedc0cbe5ef6af5efde0cf9bc02d022c546ceb Mon Sep 17 00:00:00 2001 From: David Ribeiro Alves Date: Tue, 22 Jan 2013 03:29:03 -0600 Subject: [PATCH] gce - instances api --- .../googlecompute/GoogleComputeApi.java | 11 + .../googlecompute/GoogleComputeAsyncApi.java | 10 + .../config/GoogleComputeParserModule.java | 94 ++ .../config/GoogleComputeRestClientModule.java | 85 +- .../googlecompute/domain/Instance.java | 1065 +++++++++++++++++ .../domain/InstanceTemplate.java | 507 ++++++++ .../googlecompute/features/DiskApi.java | 5 +- .../googlecompute/features/DiskAsyncApi.java | 8 +- .../googlecompute/features/InstanceApi.java | 136 +++ .../features/InstanceAsyncApi.java | 194 +++ .../functions/internal/ParseInstances.java | 67 ++ .../handlers/InstanceBinder.java | 82 ++ .../features/DiskApiExpectTest.java | 5 +- .../features/DiskApiLiveTest.java | 2 +- .../features/InstanceApiExpectTest.java | 226 ++++ .../features/InstanceApiLiveTest.java | 120 ++ .../features/KernelApiExpectTest.java | 5 +- .../features/MachineTypeApiExpectTest.java | 5 +- .../features/OperationApiExpectTest.java | 5 +- .../features/ProjectApiExpectTest.java | 5 +- .../features/ZoneApiExpectTest.java | 5 +- .../BaseGoogleComputeApiExpectTest.java | 8 + .../BaseGoogleComputeApiLiveTest.java | 31 +- .../internal/BaseGoogleComputeExpectTest.java | 2 +- .../parse/ParseInstanceListTest.java | 52 + .../parse/ParseInstanceSerialOutputTest.java | 44 + .../parse/ParseInstanceTest.java | 79 ++ .../src/test/resources/disk_insert.json | 2 +- .../resources/instance_add_access_config.json | 11 + .../src/test/resources/instance_get.json | 50 + .../src/test/resources/instance_insert.json | 1 + .../resources/instance_insert_simple.json | 1 + .../src/test/resources/instance_list.json | 57 + .../test/resources/instance_serial_port.json | 4 + 34 files changed, 2924 insertions(+), 60 deletions(-) create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Instance.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/InstanceTemplate.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceApi.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceAsyncApi.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseInstances.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/handlers/InstanceBinder.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiExpectTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiLiveTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceListTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceSerialOutputTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceTest.java create mode 100644 labs/google-compute/src/test/resources/instance_add_access_config.json create mode 100644 labs/google-compute/src/test/resources/instance_get.json create mode 100644 labs/google-compute/src/test/resources/instance_insert.json create mode 100644 labs/google-compute/src/test/resources/instance_insert_simple.json create mode 100644 labs/google-compute/src/test/resources/instance_list.json create mode 100644 labs/google-compute/src/test/resources/instance_serial_port.json diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java index acf788e50f..2a9b7fe7b8 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java @@ -22,6 +22,7 @@ import com.google.common.annotations.Beta; import org.jclouds.googlecompute.features.DiskApi; import org.jclouds.googlecompute.features.FirewallApi; import org.jclouds.googlecompute.features.ImageApi; +import org.jclouds.googlecompute.features.InstanceApi; import org.jclouds.googlecompute.features.KernelApi; import org.jclouds.googlecompute.features.MachineTypeApi; import org.jclouds.googlecompute.features.NetworkApi; @@ -33,6 +34,7 @@ import org.jclouds.rest.annotations.Delegate; import javax.ws.rs.Path; import javax.ws.rs.PathParam; + /** * Provides synchronous access to GoogleCompute. *

@@ -71,6 +73,15 @@ public interface GoogleComputeApi { @Path("/projects/{project}") ImageApi getImageApiForProject(@PathParam("project") String projectName); + /** + * Provides synchronous access to Instance features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + InstanceApi getInstanceApiForProject(@PathParam("project") String projectName); + /** * Provides synchronous access to Kernel features * diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java index 5b7c68de10..4affe63d1b 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java @@ -22,6 +22,7 @@ import com.google.common.annotations.Beta; import org.jclouds.googlecompute.features.DiskAsyncApi; import org.jclouds.googlecompute.features.FirewallAsyncApi; import org.jclouds.googlecompute.features.ImageAsyncApi; +import org.jclouds.googlecompute.features.InstanceAsyncApi; import org.jclouds.googlecompute.features.KernelAsyncApi; import org.jclouds.googlecompute.features.MachineTypeAsyncApi; import org.jclouds.googlecompute.features.NetworkAsyncApi; @@ -71,6 +72,15 @@ public interface GoogleComputeAsyncApi { @Path("/projects/{project}") ImageAsyncApi getImageApiForProject(@PathParam("project") String projectName); + /** + * Provides asynchronous access to Instance features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + InstanceAsyncApi getInstanceApiForProject(@PathParam("project") String projectName); + /** * Provides asynchronous access to Kernel features * diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java index c98365725d..e8d8ff4fa1 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java @@ -34,6 +34,8 @@ import com.google.gson.JsonSerializer; import com.google.inject.AbstractModule; import com.google.inject.Provides; import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.InstanceTemplate; import org.jclouds.googlecompute.domain.Operation; import org.jclouds.googlecompute.domain.Project; import org.jclouds.json.config.GsonModule; @@ -71,6 +73,8 @@ public class GoogleComputeParserModule extends AbstractModule { .put(Header.class, new HeaderTypeAdapter()) .put(ClaimSet.class, new ClaimSetTypeAdapter()) .put(Project.class, new ProjectTypeAdapter()) + .put(Instance.class, new InstanceTypeAdapter()) + .put(InstanceTemplate.class, new InstanceTemplateTypeAdapter()) .put(Rule.class, new RuleTypeAdapter()) .build(); } @@ -118,6 +122,96 @@ public class GoogleComputeParserModule extends AbstractModule { } } + @Singleton + private static class InstanceTemplateTypeAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(InstanceTemplate src, Type typeOfSrc, JsonSerializationContext context) { + InstanceTemplateInternal template = new InstanceTemplateInternal(src); + JsonObject instance = (JsonObject) context.serialize(template, InstanceTemplateInternal.class); + + // deal with network + JsonArray networkInterfaces = new JsonArray(); + networkInterfaces.add(context.serialize(src.getNetwork(), InstanceTemplate.Network.class)); + instance.add("networkInterfaces", networkInterfaces); + + // deal with persistent disks + if (src.getDisks() != null && !src.getDisks().isEmpty()) { + JsonArray disks = new JsonArray(); + for (InstanceTemplate.PersistentDisk persistentDisk : src.getDisks()) { + JsonObject disk = (JsonObject) context.serialize(persistentDisk, InstanceTemplate.PersistentDisk.class); + disk.addProperty("type", "PERSISTENT"); + disks.add(disk); + } + instance.add("disks", disks); + } + + // deal with metadata + if (src.getMetadata() != null && !src.getMetadata().isEmpty()) { + JsonObject metadata = (JsonObject) context.serialize(new Metadata(src.getMetadata())); + instance.add("metadata", metadata); + return instance; + } + + return instance; + } + + private static class InstanceTemplateInternal extends InstanceTemplate { + private InstanceTemplateInternal(InstanceTemplate template) { + super(template.getMachineType()); + name(template.getName()); + description(template.getDescription()); + zone(template.getZone()); + image(template.getImage()); + tags(template.getTags()); + serviceAccounts(template.getServiceAccounts()); + } + } + } + + @Singleton + private static class InstanceTypeAdapter implements JsonDeserializer { + + @Override + public Instance deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + Instance.Builder instanceBuilder = ((Instance) context.deserialize(json, + InstanceInternal.class)).toBuilder(); + JsonObject object = (JsonObject) json; + if (object.get("disks") != null) { + JsonArray disks = (JsonArray) object.get("disks"); + for (JsonElement element : disks) { + JsonObject disk = (JsonObject) element; + if (disk.get("type").getAsString().equals("PERSISTENT")) { + instanceBuilder.addDisk((Instance.PersistentAttachedDisk) context.deserialize(disk, + Instance.PersistentAttachedDisk.class)); + } else { + instanceBuilder.addDisk((Instance.AttachedDisk) context.deserialize(disk, + Instance.AttachedDisk.class)); + } + } + + } + + return Instance.builder().fromInstance(instanceBuilder.build()).build(); + } + + + private static class InstanceInternal extends Instance { + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "tags", "image", "machineType", + "status", "statusMessage", "zone", "networkInterfaces", "metadata", "serviceAccounts" + }) + private InstanceInternal(String id, Date creationTimestamp, URI selfLink, String name, String description, + Set tags, URI image, URI machineType, Status status, String statusMessage, + URI zone, Set networkInterfaces, Metadata metadata, + Set serviceAccounts) { + super(id, creationTimestamp, selfLink, name, description, tags, image, machineType, + status, statusMessage, zone, networkInterfaces, null, metadata, serviceAccounts); + } + } + } + /** * Parser for Metadata. */ diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java index 44a8a59936..e36eaee0b7 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java @@ -18,14 +18,14 @@ */ package org.jclouds.googlecompute.config; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Suppliers.compose; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import javax.inject.Singleton; - +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; import org.jclouds.domain.Credentials; import org.jclouds.googlecompute.GoogleComputeApi; import org.jclouds.googlecompute.GoogleComputeAsyncApi; @@ -36,6 +36,8 @@ import org.jclouds.googlecompute.features.FirewallApi; import org.jclouds.googlecompute.features.FirewallAsyncApi; import org.jclouds.googlecompute.features.ImageApi; import org.jclouds.googlecompute.features.ImageAsyncApi; +import org.jclouds.googlecompute.features.InstanceApi; +import org.jclouds.googlecompute.features.InstanceAsyncApi; import org.jclouds.googlecompute.features.KernelApi; import org.jclouds.googlecompute.features.KernelAsyncApi; import org.jclouds.googlecompute.features.MachineTypeApi; @@ -51,22 +53,24 @@ import org.jclouds.googlecompute.features.ZoneAsyncApi; import org.jclouds.googlecompute.handlers.GoogleComputeErrorHandler; import org.jclouds.googlecompute.predicates.OperationDonePredicate; import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.Uris; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.ServerError; import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; +import org.jclouds.location.Provider; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.config.RestClientModule; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Splitter; -import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.inject.Provides; -import com.google.inject.TypeLiteral; +import javax.inject.Named; +import javax.inject.Singleton; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Suppliers.compose; /** * Configures the GoogleCompute connection. @@ -79,6 +83,7 @@ public class GoogleComputeRestClientModule extends RestClientModule supplyProject( - @org.jclouds.location.Provider final Supplier creds) { + public Supplier supplyProject(@org.jclouds.location.Provider final Supplier creds) { return compose(new Function() { public String apply(Credentials in) { - checkState(in.identity.indexOf("@") != 1, "identity should be in project_id@developer.gserviceaccount.com format"); + checkState(in.identity.indexOf("@") != 1, "identity should be in project_id@developer.gserviceaccount.com" + + " format"); return Iterables.get(Splitter.on("@").split(in.identity), 0); } }, creds); } + + @Provides + @Singleton + @Named("machineTypes") + public Function provideMachineTypeNameToURIFunction(final @Provider Supplier endpoint, + final @UserProject Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()).appendPath + ("/machineTypes/").appendPath(input).build(); + } + }; + } + + @Provides + @Singleton + @Named("networks") + public Function provideNetworkNameToURIFunction(final @Provider Supplier endpoint, + final @UserProject Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()).appendPath + ("/networks/").appendPath(input).build(); + } + }; + } + + @Provides + @Singleton + @Named("zones") + public Function provideZoneNameToURIFunction(final @Provider Supplier endpoint, + final @UserProject Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()).appendPath + ("/zones/").appendPath(input).build(); + } + }; + } } diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Instance.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Instance.java new file mode 100644 index 0000000000..58be58b257 --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Instance.java @@ -0,0 +1,1065 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.domain; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import org.jclouds.javax.annotation.Nullable; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Map; +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.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a virtual machine. + * + * @author David Alves + * @see + */ +@Beta +public class Instance extends Resource { + + public enum Status { + PROVISIONING, + STAGING, + RUNNING, + STOPPING, + STOPPED, + TERMINATED + } + + protected final Set tags; + protected final URI image; + protected final URI machineType; + protected final Status status; + protected final Optional statusMessage; + protected final URI zone; + protected final Set networkInterfaces; + protected final Set disks; + protected final Map metadata; + protected final Set serviceAccounts; + + protected Instance(String id, Date creationTimestamp, URI selfLink, String name, String description, + Set tags, URI image, URI machineType, Status status, String statusMessage, + URI zone, Set networkInterfaces, Set disks, + Map metadata, Set serviceAccounts) { + super(Kind.INSTANCE, checkNotNull(id, "id"), fromNullable(creationTimestamp), checkNotNull(selfLink, "selfLink"), + checkNotNull(name, "name"), fromNullable(description)); + this.tags = tags == null ? ImmutableSet.of() : tags; + this.image = checkNotNull(image, "image"); + this.machineType = checkNotNull(machineType, "machineType of %s", name); + this.status = checkNotNull(status, "status"); + this.statusMessage = fromNullable(statusMessage); + this.zone = checkNotNull(zone, "zone of %s", name); + this.networkInterfaces = networkInterfaces == null ? ImmutableSet.of() : networkInterfaces; + this.disks = disks == null ? ImmutableSet.of() : disks; + this.metadata = metadata == null ? ImmutableMap.of() : metadata; + this.serviceAccounts = serviceAccounts == null ? ImmutableSet.of() : serviceAccounts; + } + + /** + * Used to identify valid sources or targets for network firewalls. Provided by the client when the instance is + * created. Each tag must be unique, must be 1-63 characters long, and comply with RFC1035. + * + * @return an optional set of tags applied to this instance. + */ + public Set getTags() { + return tags; + } + + /** + * @return the URL of the disk image resource to be to be installed on this instance. + */ + public URI getImage() { + return image; + } + + /** + * @return URL of the machine type resource describing which machine type to use to host the instance. + */ + public URI getMachineType() { + return machineType; + } + + /** + * @return Instance status + */ + public Status getStatus() { + return status; + } + + /** + * @return an optional, human-readable explanation of the status. + */ + @Nullable + public Optional getStatusMessage() { + return statusMessage; + } + + /** + * @return URL of the zone resource describing where this instance should be hosted; provided by the client when + * the instance is created. + */ + public URI getZone() { + return zone; + } + + /** + * @return set of NetworkInterfaces + * @see NetworkInterface + */ + public Set getNetworkInterfaces() { + return networkInterfaces; + } + + /** + * @return array of disks associated with this instance. Persistent disks must be created before + * you can assign them. + * @see org.jclouds.googlecompute.domain.Instance.AttachedDisk + */ + public Set getDisks() { + return disks; + } + + /** + * @return metadata for this instance + */ + public Map getMetadata() { + return metadata; + } + + /** + * @return list of service accounts each with specified scopes. + * @see ServiceAccount + */ + public Set getServiceAccounts() { + return serviceAccounts; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("tags", tags) + .add("image", image) + .add("machineType", machineType) + .add("status", status) + .add("statusMessage", statusMessage.orNull()) + .add("zone", zone) + .add("networkInterfaces", networkInterfaces) + .add("disks", disks) + .add("metadata", metadata) + .add("serviceAccounts", serviceAccounts); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromInstance(this); + } + + public static final class Builder extends Resource.Builder { + + private ImmutableSet.Builder tags = ImmutableSet.builder(); + private URI image; + private URI machineType; + private Status status; + private String statusMessage; + private URI zone; + private ImmutableSet.Builder networkInterfaces = ImmutableSet.builder(); + private ImmutableSet.Builder disks = ImmutableSet.builder(); + private ImmutableMap.Builder metadata = ImmutableMap.builder(); + private ImmutableSet.Builder serviceAccounts = ImmutableSet.builder(); + + /** + * @see Instance#getTags() + */ + public Builder addTag(String tag) { + this.tags.add(tag); + return this; + } + + /** + * @see Instance#getTags() + */ + public Builder tags(Set tags) { + this.tags.addAll(tags); + return this; + } + + /** + * @see Instance#getImage() + */ + public Builder image(URI image) { + this.image = image; + return this; + } + + /** + * @see Instance#getMachineType() + */ + public Builder machineType(URI machineType) { + this.machineType = machineType; + return this; + } + + /** + * @see Instance#getStatus() + */ + public Builder status(Status status) { + this.status = status; + return this; + } + + /** + * @see Instance#getStatusMessage() + */ + public Builder statusMessage(String statusMessage) { + this.statusMessage = statusMessage; + return this; + } + + /** + * @see Instance#getZone() + */ + public Builder zone(URI zone) { + this.zone = zone; + return this; + } + + /** + * @see Instance#getNetworkInterfaces() + */ + public Builder addNetworkInterface(NetworkInterface networkInterface) { + this.networkInterfaces.add(networkInterface); + return this; + } + + /** + * @see Instance#getNetworkInterfaces() + */ + public Builder networkInterfaces(Set networkInterfaces) { + this.networkInterfaces.addAll(networkInterfaces); + return this; + } + + /** + * @see Instance#getDisks() + */ + public Builder addDisk(AttachedDisk disk) { + this.disks.add(disk); + return this; + } + + /** + * @see Instance#getDisks() + */ + public Builder disks(Set disks) { + this.disks.addAll(disks); + return this; + } + + /** + * @see Instance#getMetadata() + */ + public Builder metadata(Map metadata) { + this.metadata = new ImmutableMap.Builder().putAll(metadata); + return this; + } + + /** + * @see Instance#getMetadata() + */ + public Builder addMetadata(String key, String value) { + this.metadata.put(checkNotNull(key, "key"), checkNotNull(value, "value of %s", key)); + return this; + } + + /** + * @see Instance#getServiceAccounts() + */ + public Builder addServiceAccount(ServiceAccount serviceAccount) { + this.serviceAccounts.add(serviceAccount); + return this; + } + + /** + * @see Instance#getServiceAccounts() + */ + public Builder serviceAccoutns(Set serviceAccounts) { + this.serviceAccounts.addAll(serviceAccounts); + return this; + } + + + @Override + protected Builder self() { + return this; + } + + public Instance build() { + return new Instance(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, tags.build(), image, machineType, status, statusMessage, zone, + networkInterfaces.build(), disks.build(), metadata.build(), serviceAccounts.build()); + } + + public Builder fromInstance(Instance in) { + return super.fromResource(in) + .tags(in.getTags()) + .image(in.getImage()) + .machineType(in.getMachineType()) + .status(in.getStatus()) + .statusMessage(in.getStatusMessage().orNull()) + .zone(in.getZone()) + .networkInterfaces(in.getNetworkInterfaces()) + .disks(in.getDisks()) + .metadata(in.getMetadata()) + .serviceAccoutns(in.getServiceAccounts()); + } + } + + /** + * A disk attached to an Instance. + * + * @see + */ + public static class AttachedDisk { + + private final int index; + + public AttachedDisk(Integer index) { + this.index = checkNotNull(index, "index"); + } + + public boolean isPersistent() { + return false; + } + + /** + * @return a zero-based index to assign to this disk, where 0 is reserved for the boot disk. + */ + public int getIndex() { + return index; + } + + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(index); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AttachedDisk that = AttachedDisk.class.cast(obj); + return equal(this.index, that.index); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("index", index); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static AttachedDisk ephemeralDiskAtIndex(Integer index) { + return new AttachedDisk(index); + } + } + + public static class PersistentAttachedDisk extends AttachedDisk { + + public enum Mode { + READ_WRITE, + READ_ONLY + } + + @ConstructorProperties({"mode", "source", "deviceName", "index", "deleteOnTerminate"}) + public PersistentAttachedDisk(Mode mode, URI source, String deviceName, Integer index, + boolean deleteOnTerminate) { + super(index); + this.mode = checkNotNull(mode, "mode"); + this.source = checkNotNull(source, "source"); + this.deviceName = fromNullable(deviceName); + this.deleteOnTerminate = deleteOnTerminate; + } + + private final Mode mode; + private final URI source; + private final boolean deleteOnTerminate; + private final Optional deviceName; + + @Override + public boolean isPersistent() { + return true; + } + + /** + * @return the mode in which to attach this disk, either READ_WRITE or READ_ONLY. + */ + public Mode getMode() { + return mode; + } + + /** + * @return the URL of the persistent disk resource. + */ + public URI getSource() { + return source; + } + + /** + * @return Must be unique within the instance when specified. This represents a unique + * device name that is reflected into the /dev/ tree of a Linux operating system running within the + * instance. If not specified, a default will be chosen by the system. + */ + public Optional getDeviceName() { + return deviceName; + } + + + /** + * @return If true, delete the disk and all its data when the associated instance is deleted. + */ + public boolean isDeleteOnTerminate() { + return deleteOnTerminate; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + + private Mode mode; + private URI source; + private String deviceName; + private Integer index; + private boolean deleteOnTerminate; + + /** + * @see org.jclouds.googlecompute.domain.Instance.PersistentAttachedDisk#getMode() + */ + public Builder mode(Mode mode) { + this.mode = mode; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.PersistentAttachedDisk#getSource() + */ + public Builder source(URI source) { + this.source = source; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.PersistentAttachedDisk#getDeviceName() + */ + public Builder deviceName(String deviceName) { + this.deviceName = deviceName; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.AttachedDisk#getIndex() + */ + public Builder index(Integer index) { + this.index = index; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.PersistentAttachedDisk#isDeleteOnTerminate() + */ + public Builder deleteOnTerminate(Boolean deleteOnTerminate) { + this.deleteOnTerminate = deleteOnTerminate; + return this; + } + + public PersistentAttachedDisk build() { + return new PersistentAttachedDisk(this.mode, this.source, this.deviceName, this.index, + this.deleteOnTerminate); + } + + public Builder fromPersistentAttachedDisk(PersistentAttachedDisk in) { + return this.mode(in.getMode()) + .source(in.getSource()) + .deviceName(in.getDeviceName().orNull()) + .index(in.getIndex()) + .deleteOnTerminate(in.isDeleteOnTerminate()); + } + } + } + + /** + * A network interface for an Instance. + * + * @see + */ + public static final class NetworkInterface { + + private final String name; + private final URI network; + private final String networkIP; + private final Set accessConfigs; + + @ConstructorProperties({ + "name", "network", "networkIP", "accessConfigs" + }) + private NetworkInterface(String name, URI network, String networkIP, + Set accessConfigs) { + this.name = checkNotNull(name, "name"); + this.network = checkNotNull(network, "network"); + this.networkIP = checkNotNull(networkIP, "networkIP"); + this.accessConfigs = accessConfigs == null ? ImmutableSet.of() : accessConfigs; + } + + /** + * @return the name of the network interface + */ + public String getName() { + return name; + } + + /** + * @return URL of the network resource attached to this interface. + */ + public URI getNetwork() { + return network; + } + + /** + * @return An IPV4 internal network address to assign to this instance. + */ + public String getNetworkIP() { + return networkIP; + } + + /** + * @return array of access configurations for this interface. + */ + public Set getAccessConfigs() { + return accessConfigs; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, network, networkIP, accessConfigs); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + NetworkInterface that = NetworkInterface.class.cast(obj); + return equal(this.name, that.name) + && equal(this.network, that.network); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("name", name) + .add("network", network).add("networkIP", networkIP).add("accessConfigs", + accessConfigs); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromNetworkInterface(this); + } + + public static class Builder { + + private String name; + private URI network; + private String networkIP; + private ImmutableSet.Builder accessConfigs = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface#getNetwork() + */ + public Builder network(URI network) { + this.network = network; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface#getNetworkIP() + */ + public Builder networkIP(String networkIP) { + this.networkIP = networkIP; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface#getAccessConfigs() + */ + public Builder addAccessConfig(AccessConfig accessConfig) { + this.accessConfigs.add(accessConfig); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface#getAccessConfigs() + */ + public Builder accessConfigs(Set accessConfigs) { + this.accessConfigs = ImmutableSet.builder(); + this.accessConfigs.addAll(accessConfigs); + return this; + } + + public NetworkInterface build() { + return new NetworkInterface(this.name, this.network, this.networkIP, this.accessConfigs.build()); + } + + public Builder fromNetworkInterface(NetworkInterface in) { + return this.network(in.getNetwork()) + .networkIP(in.getNetworkIP()) + .accessConfigs(in.getAccessConfigs()); + } + } + + /** + * Access configuration to an instance's network. + *

+ * This specifies how this interface is configured to interact with other network services, + * such as connecting to the internet. Currently, ONE_TO_ONE_NAT is the only access config supported. + */ + public static final class AccessConfig { + + public enum Type { + ONE_TO_ONE_NAT + } + + private String name; + private Type type; + private Optional natIP; + + @ConstructorProperties({ + "name", "type", "natIP" + }) + private AccessConfig(String name, Type type, String natIP) { + this.name = checkNotNull(name, "name"); + this.type = checkNotNull(type, "type"); + this.natIP = fromNullable(natIP); + } + + /** + * @return name of this access configuration. + */ + public String getName() { + return name; + } + + /** + * @return type of configuration. Must be set to ONE_TO_ONE_NAT. This configures port-for-port NAT to the + * internet. + */ + public Type getType() { + return type; + } + + /** + * @return an external IP address associated with this instance, if there is one. + */ + @Nullable + public Optional getNatIP() { + return natIP; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, type, natIP); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AccessConfig that = AccessConfig.class.cast(obj); + return equal(this.name, that.name) + && equal(this.type, that.type) + && equal(this.natIP, that.natIP); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("name", name).add("type", type).add("natIP", natIP); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromAccessConfig(this); + } + + public static class Builder { + + private String name; + private Type type; + private String natIP; + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface.AccessConfig#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface.AccessConfig#getType() + */ + public Builder type(Type type) { + this.type = type; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.NetworkInterface.AccessConfig#getNatIP() + */ + public Builder natIP(String natIP) { + this.natIP = natIP; + return this; + } + + public AccessConfig build() { + return new AccessConfig(name, type, natIP); + } + + public Builder fromAccessConfig(AccessConfig in) { + return this.name(in.getName()) + .type(in.getType()) + .natIP(in.getNatIP().orNull()); + } + } + } + } + + /** + * The output of an instance's serial port; + * + * @author David Alves + * @see + */ + public static final class SerialPortOutput { + + private final Optional selfLink; + private final String contents; + + @ConstructorProperties({ + "selfLink", "contents" + }) + public SerialPortOutput(String selfLink, String contents) { + this.selfLink = fromNullable(selfLink); + this.contents = checkNotNull(contents, "contents"); + } + + /** + * @return unique identifier for the resource; defined by the server (output only). + */ + public Optional getSelfLink() { + return selfLink; + } + + /** + * @return the contents of the console output. + */ + public String getContents() { + return contents; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(selfLink, contents); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SerialPortOutput that = SerialPortOutput.class.cast(obj); + return equal(this.selfLink, that.selfLink); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("selfLink", selfLink).add("contents", contents); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromInstanceSerialPortOutput(this); + } + + public static final class Builder { + + private String selfLink; + private String contents; + + /** + * @see org.jclouds.googlecompute.domain.Instance.SerialPortOutput#getSelfLink() + */ + public Builder selfLink(String selfLink) { + this.selfLink = checkNotNull(selfLink); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.SerialPortOutput#getContents() + */ + public Builder contents(String contents) { + this.contents = contents; + return this; + } + + public SerialPortOutput build() { + return new SerialPortOutput(selfLink, contents); + } + + public Builder fromInstanceSerialPortOutput(SerialPortOutput in) { + return this.selfLink(in.getSelfLink().orNull()) + .contents(in.getContents()); + } + } + + } + + /** + * A service account for which access tokens are to be made available to the instance through metadata queries. + * + * @author David Alves + * @see + */ + public static final class ServiceAccount { + + private final String email; + private final Set scopes; + + @ConstructorProperties({ + "email", "scopes" + }) + public ServiceAccount(String email, Set scopes) { + this.email = checkNotNull(email, "email"); + this.scopes = checkNotNull(scopes, "scopes"); + } + + /** + * @return email address of the service account. + */ + public String getEmail() { + return email; + } + + /** + * @return the list of scopes to be made available for this service account. + */ + public Set getScopes() { + return scopes; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(email, scopes); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + ServiceAccount that = ServiceAccount.class.cast(obj); + return equal(this.email, that.email) + && equal(this.scopes, that.scopes); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("email", email).add("scopes", scopes); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromInstanceServiceAccount(this); + } + + public static final class Builder { + + private String email; + private ImmutableSet.Builder scopes = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecompute.domain.Instance.ServiceAccount#getEmail() + */ + public Builder email(String email) { + this.email = checkNotNull(email); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.ServiceAccount#getScopes() + */ + public Builder addScopes(String scopes) { + this.scopes.add(scopes); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance.ServiceAccount#getScopes() + */ + public Builder scopes(Set scopes) { + this.scopes.addAll(scopes); + return this; + } + + public ServiceAccount build() { + return new ServiceAccount(email, scopes.build()); + } + + public Builder fromInstanceServiceAccount(ServiceAccount in) { + return this.email(in.getEmail()).scopes(in.getScopes()); + } + } + } +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/InstanceTemplate.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/InstanceTemplate.java new file mode 100644 index 0000000000..e77db60d5b --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/InstanceTemplate.java @@ -0,0 +1,507 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.domain; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Optional information for creating an instance. + * + * @author David Alves + */ +public class InstanceTemplate { + + protected String name; + protected String description; + protected URI machineType; + protected URI zone; + protected URI image; + protected Set tags = Sets.newLinkedHashSet(); + protected Set serviceAccounts = Sets.newLinkedHashSet(); + + protected transient Set disks = Sets.newLinkedHashSet(); + protected transient Network network; + protected transient String networkName; + protected transient Map metadata = Maps.newLinkedHashMap(); + protected transient String machineTypeName; + protected transient String zoneName; + + + protected InstanceTemplate(URI machineType) { + this.machineType = checkNotNull(machineType, "machineType"); + } + + protected InstanceTemplate(String machineTypeName) { + this.machineTypeName = checkNotNull(machineTypeName, "machineTypeName"); + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getName() + */ + public InstanceTemplate name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDescription() + */ + public InstanceTemplate description(String description) { + this.description = description; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getImage() + */ + public InstanceTemplate image(URI image) { + this.image = image; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMachineType() + */ + public InstanceTemplate machineType(URI machineType) { + this.machineType = machineType; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMachineType() + */ + public InstanceTemplate machineType(String machineTypeName) { + this.machineTypeName = machineTypeName; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getZone() + */ + public InstanceTemplate zone(String zoneName) { + this.zoneName = zoneName; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getZone() + */ + public InstanceTemplate zone(URI zone) { + this.zone = zone; + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getTags() + */ + public InstanceTemplate addTag(String tag) { + this.tags.add(checkNotNull(tag, "tag")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getTags() + */ + public InstanceTemplate tags(Set tags) { + this.tags = Sets.newLinkedHashSet(); + this.tags.addAll(checkNotNull(tags, "tags")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source) { + this.disks.add(new PersistentDisk(mode, source, null, null)); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source, String deviceName, Boolean deleteOnTerminate) { + this.disks.add(new PersistentDisk(mode, source, deviceName, deleteOnTerminate)); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDisks() + */ + public InstanceTemplate disks(Set disks) { + this.disks = Sets.newLinkedHashSet(); + this.disks.addAll(checkNotNull(disks, "disks")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getNetworkInterfaces() + */ + public InstanceTemplate network(URI network) { + // by default use the provided network and set to obtain an external IP address and not to specify an internal IP + // this behavior can be overriden by using network(Network network) + this.network = new Network(checkNotNull(network, "network"), null, + ImmutableSet.of(Instance.NetworkInterface.AccessConfig.builder() + .name("external") + .type(Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT) + .build())); + return this; + } + + private InstanceTemplate network(Network network) { + this.network = network; + return this; + } + + public InstanceTemplate networkName(String networkName) { + this.networkName = networkName; + return this; + } + + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMetadata() + */ + public InstanceTemplate addMetadata(String key, String value) { + this.metadata.put(checkNotNull(key, "key"), checkNotNull(value, "value of %", key)); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMetadata() + */ + public InstanceTemplate metadata(Map metadata) { + this.metadata = Maps.newLinkedHashMap(); + this.metadata.putAll(checkNotNull(metadata, "metadata")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getServiceAccounts() + */ + public InstanceTemplate addServiceAccount(Instance.ServiceAccount serviceAccount) { + this.serviceAccounts.add(checkNotNull(serviceAccount, "serviceAccount")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getServiceAccounts() + */ + public InstanceTemplate serviceAccounts(Set serviceAccounts) { + this.serviceAccounts = Sets.newLinkedHashSet(); + this.serviceAccounts.addAll(checkNotNull(serviceAccounts, "serviceAccounts")); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDescription() + */ + public String getDescription() { + return description; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getDisks() + */ + public Set getDisks() { + return disks; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getImage() + */ + public URI getImage() { + return image; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMachineType() + */ + public URI getMachineType() { + return machineType; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMachineType() + */ + public String getMachineTypeName() { + return machineTypeName; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getMetadata() + */ + public Map getMetadata() { + return metadata; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getNetworkInterfaces() + */ + public Network getNetwork() { + return network; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getNetworkInterfaces() + */ + public String getNetworkName() { + return networkName; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getServiceAccounts() + */ + public Set getServiceAccounts() { + return serviceAccounts; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getTags() + */ + public Set getTags() { + return tags; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getName() + */ + public String getName() { + return name; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getZone() + */ + public URI getZone() { + return zone; + } + + /** + * @see org.jclouds.googlecompute.domain.Instance#getZone() + */ + public String getZoneName() { + return zoneName; + } + + public static Builder builder() { + return new Builder(); + } + + public static InstanceTemplate fromInstance(Instance instance) { + return Builder.fromInstance(instance); + } + + public static InstanceTemplate fromInstanceTemplate(InstanceTemplate instanceTemplate) { + return Builder.fromInstanceTemplate(instanceTemplate); + } + + public static class Builder { + + public InstanceTemplate forMachineTypeAndNetwork(URI machineType, URI network) { + return new InstanceTemplate(machineType).network(network); + } + + public InstanceTemplate forMachineTypeAndNetwork(URI machineType, Network network) { + return new InstanceTemplate(machineType).network(network); + } + + public InstanceTemplate forMachineTypeAndNetwork(String machineTypeName, String networkName) { + return new InstanceTemplate(machineTypeName).networkName(networkName); + } + + /** + * Creates instance options based on another instance. + * All properties are the same as the original instance's except: + * - disks (persistent disks are only attached to an instance) + * - networkInterfaces (these are instance specific) + */ + public static InstanceTemplate fromInstance(Instance instance) { + return InstanceTemplate.builder() + .forMachineTypeAndNetwork(instance.getMachineType(), + instance.getNetworkInterfaces().iterator().next().getNetwork()) + .description(instance.getDescription().orNull()) + .tags(instance.getTags()) + .image(instance.getImage()) + .metadata(instance.getMetadata()) + .zone(instance.getZone()) + .serviceAccounts(instance.getServiceAccounts()); + } + + public static InstanceTemplate fromInstanceTemplate(InstanceTemplate instanceTemplate) { + return InstanceTemplate.builder() + .forMachineTypeAndNetwork(instanceTemplate.getMachineType(), instanceTemplate.getNetwork()) + .name(instanceTemplate.getName()) + .description(instanceTemplate.getDescription()) + .zone(instanceTemplate.getZone()) + .image(instanceTemplate.getImage()) + .tags(instanceTemplate.getTags()) + .disks(instanceTemplate.getDisks()) + .metadata(instanceTemplate.getMetadata()) + .serviceAccounts(instanceTemplate.getServiceAccounts()); + } + } + + + public static class PersistentDisk { + + public enum Mode { + READ_WRITE, + READ_ONLY + } + + public PersistentDisk(Mode mode, URI source, String deviceName, Boolean deleteOnTerminate) { + this.mode = checkNotNull(mode, "mode"); + this.source = checkNotNull(source, "source"); + this.deviceName = deviceName; + this.deleteOnTerminate = deleteOnTerminate; + } + + private final Mode mode; + private final URI source; + private final Boolean deleteOnTerminate; + private final String deviceName; + + /** + * @return the mode in which to attach this disk, either READ_WRITE or READ_ONLY. + */ + public Mode getMode() { + return mode; + } + + /** + * @return the URL of the persistent disk resource. + */ + public URI getSource() { + return source; + } + + /** + * @return Must be unique within the instance when specified. This represents a unique + * device name that is reflected into the /dev/ tree of a Linux operating system running within the + * instance. If not specified, a default will be chosen by the system. + */ + public String getDeviceName() { + return deviceName; + } + + + /** + * @return If true, delete the disk and all its data when the associated instance is deleted. + */ + public boolean isDeleteOnTerminate() { + return deleteOnTerminate; + } + } + + public static class Network { + + private final URI network; + private final String networkIP; + private final Set accessConfigs; + + public Network(URI network, String networkIP, Set + accessConfigs) { + this.networkIP = networkIP; + this.network = checkNotNull(network, "network"); + this.accessConfigs = accessConfigs; + } + + public Set getAccessConfigs() { + return accessConfigs; + } + + public URI getNetwork() { + return network; + } + + public String getNetworkIP() { + return networkIP; + } + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof InstanceTemplate) { + final InstanceTemplate other = InstanceTemplate.class.cast(object); + return equal(description, other.description) + && equal(tags, other.tags) + && equal(image, other.image) + && equal(disks, other.disks) + && equal(network, other.network) + && equal(metadata, other.metadata) + && equal(serviceAccounts, other.serviceAccounts); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(description, tags, image, disks, network, metadata, serviceAccounts); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + Objects.ToStringHelper toString = Objects.toStringHelper("") + .omitNullValues(); + toString.add("description", description); + if (tags.size() > 0) + toString.add("tags", tags); + if (disks.size() > 0) + toString.add("disks", disks); + if (metadata.size() > 0) + toString.add("metadata", metadata); + if (serviceAccounts.size() > 0) + toString.add("serviceAccounts", serviceAccounts); + toString.add("image", image); + toString.add("networkInterfaces", network); + return toString; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskApi.java index 026efbd280..43324b2d4e 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskApi.java @@ -48,13 +48,14 @@ public interface DiskApi { /** * Creates a persistent disk resource in the specified project specifying the size of the disk. * + * * @param diskName the name of disk. - * @param zone the URi of the zone where the disk is to be created. * @param sizeGb the size of the disk + * @param zone the URi of the zone where the disk is to be created. * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to * you, and look for the status field. */ - Operation insert(String diskName, URI zone, int sizeGb); + Operation createInZone(String diskName, int sizeGb, URI zone); /** * Deletes the specified persistent disk resource. diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskAsyncApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskAsyncApi.java index f4f0c99bb1..82b070dce0 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskAsyncApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/DiskAsyncApi.java @@ -76,7 +76,7 @@ public interface DiskAsyncApi { ListenableFuture get(@PathParam("disk") String diskName); /** - * @see DiskApi#insert(String, java.net.URI, int) + * @see DiskApi#createInZone(String, int, java.net.URI) */ @POST @Consumes(MediaType.APPLICATION_JSON) @@ -84,9 +84,9 @@ public interface DiskAsyncApi { @Path("/disks") @OAuthScopes({COMPUTE_SCOPE}) @MapBinder(BindToJsonPayload.class) - ListenableFuture insert(@PayloadParam("name") String diskName, - @PayloadParam("zone") URI zone, - @PayloadParam("sizeGb") int sizeGb); + ListenableFuture createInZone(@PayloadParam("name") String diskName, + @PayloadParam("sizeGb") int sizeGb, + @PayloadParam("zone") URI zone); /** * @see DiskApi#delete(String) diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceApi.java new file mode 100644 index 0000000000..a5933795fc --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceApi.java @@ -0,0 +1,136 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Operation; +import org.jclouds.googlecompute.domain.InstanceTemplate; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; + +/** + * Provides synchronous access to Instances via their REST API. + *

+ * + * @author David Alves + * @see InstanceAsyncApi + * @see + */ +public interface InstanceApi { + + /** + * Returns the specified instance resource. + * + * @param instanceName name of the instance resource to return. + * @return an Instance resource + */ + public Instance get(String instanceName); + + /** + * Creates a instance resource in the specified project using the data included in the request. + * + * @param instanceName this name of the instance to be created + * @param template the instance template + * @param zone the name of the zone where the instance will be created + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + public Operation createInZone(String instanceName, InstanceTemplate template, String zone); + + /** + * Deletes the specified instance resource. + * + * @param instanceName name of the instance resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the instance did not exist the result is null. + */ + public Operation delete(String instanceName); + + /** + * @see InstanceApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + public ListPage listFirstPage(); + + /** + * @see InstanceApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + public ListPage listAtMarker(@Nullable String marker); + + /** + * Retrieves the list of instance resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecompute.domain.ListPage + */ + public ListPage listAtMarker(@Nullable String marker, @Nullable ListOptions listOptions); + + /** + * @see InstanceApi#list(org.jclouds.googlecompute.options.ListOptions) + */ + public PagedIterable list(); + + /** + * A paged version of InstanceApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see InstanceApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + public PagedIterable list(@Nullable ListOptions listOptions); + + /** + * Adds an access config to an instance's network interface. + * + * @param instanceName the instance name. + * @param accessConfig the AccessConfig to add. + * @param networkInterfaceName network interface name. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the instance did not exist the result is null. + */ + public Operation addAccessConfigToNic(String instanceName, Instance.NetworkInterface.AccessConfig accessConfig, + String networkInterfaceName); + + /** + * Deletes an access config from an instance's network interface. + * + * @param instanceName the instance name. + * @param accessConfigName the name of the access config to delete + * @param networkInterfaceName network interface name. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the instance did not exist the result is null. + */ + public Operation deleteAccessConfigFromNic(String instanceName, String accessConfigName, + String networkInterfaceName); + + /** + * Returns the specified instance's serial port output. + * + * @param instanceName the instance name. + * @return if successful, this method returns a SerialPortOutput containing the instance's serial output. + */ + public Instance.SerialPortOutput getSerialPortOutput(String instanceName); +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceAsyncApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceAsyncApi.java new file mode 100644 index 0000000000..ac74ad7aed --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/InstanceAsyncApi.java @@ -0,0 +1,194 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.InstanceTemplate; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Operation; +import org.jclouds.googlecompute.functions.internal.ParseInstances; +import org.jclouds.googlecompute.handlers.InstanceBinder; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import static org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import static org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import static org.jclouds.Fallbacks.NullOnNotFoundOr404; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_SCOPE; + +/** + * Provides asynchronous access to Instances via their REST API. + * + * @author David Alves + * @see InstanceApi + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface InstanceAsyncApi { + + /** + * @see InstanceApi#get(String) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances/{instance}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture get(@PathParam("instance") String instanceName); + + /** + * @see InstanceApi#createInZone(String, org.jclouds.googlecompute.domain.InstanceTemplate, String) + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(InstanceBinder.class) + ListenableFuture createInZone(@PayloadParam("name") String instanceName, + @PayloadParam("template") InstanceTemplate template, + @PayloadParam("zone") String zone); + + /** + * @see InstanceApi#delete(String) + */ + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances/{instance}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture delete(@PathParam("instance") String instanceName); + + /** + * @see InstanceApi#listFirstPage() + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listFirstPage(); + + /** + * @see InstanceApi#listAtMarker(String) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listAtMarker(@Nullable String marker); + + /** + * @see InstanceApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listAtMarker(@Nullable String marker, ListOptions options); + + /** + * @see InstanceApi#list() + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Transform(ParseInstances.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + ListenableFuture> list(); + + /** + * @see InstanceApi#list(org.jclouds.googlecompute.options.ListOptions) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Transform(ParseInstances.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + ListenableFuture> list(ListOptions options); + + /** + * @see InstanceApi#addAccessConfigToNic(String, Instance.NetworkInterface.AccessConfig, String) + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/instances/{instance}/addAccessConfig") + @OAuthScopes({COMPUTE_SCOPE}) + ListenableFuture addAccessConfigToNic(@PathParam("instance") String instanceName, + @BinderParam(BindToJsonPayload.class) + Instance.NetworkInterface.AccessConfig accessConfig, + @QueryParam("network_interface") String networkInterfaceName); + + /** + * @see InstanceApi#deleteAccessConfigFromNic(String, String, String) + */ + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances/{instance}/deleteAccessConfig") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture deleteAccessConfigFromNic(@PathParam("instance") String instanceName, + @QueryParam("access_config") String accessConfigName, + @QueryParam("network_interface") String networkInterfaceName); + + /** + * @see InstanceApi#getSerialPortOutput(String) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/instances/{instance}/serialPort") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture getSerialPortOutput(@PathParam("instance") String instanceName); +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseInstances.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseInstances.java new file mode 100644 index 0000000000..176b55a07d --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseInstances.java @@ -0,0 +1,67 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.functions.internal; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecompute.GoogleComputeApi; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import javax.inject.Inject; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author David Alves + */ +public class ParseInstances extends ParseJson> { + + @Inject + public ParseInstances(Json json) { + super(json, new TypeLiteral>() {}); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeApi api; + + @Inject + protected ToPagedIterable(GoogleComputeApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getInstanceApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/handlers/InstanceBinder.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/handlers/InstanceBinder.java new file mode 100644 index 0000000000..119b8136a5 --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/handlers/InstanceBinder.java @@ -0,0 +1,82 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.handlers; + +import com.google.common.base.Function; +import org.jclouds.googlecompute.domain.InstanceTemplate; +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.net.URI; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author David Alves + */ +public class InstanceBinder implements MapBinder { + + @Inject + private BindToJsonPayload jsonBinder; + + @Inject + @Named("machineTypes") + Function machineTypesToURI; + + @Inject + @Named("networks") + Function networksToURI; + + @Inject + @Named("zones") + Function zonesToURI; + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Map postParams) { + InstanceTemplate template = (InstanceTemplate) checkNotNull(postParams.get("template"), "template"); + template.name(checkNotNull(postParams.get("name"), "name").toString()); + template.zone(zonesToURI.apply((String) checkNotNull(postParams.get("zone"), "zone"))); + if (template.getNetworkName() != null) { + template.network(networksToURI.apply(template.getNetworkName())); + } + + if (template.getMachineTypeName() != null) { + template.machineType(machineTypesToURI.apply(template.getMachineTypeName())); + } + template.zone((String) null); + template.machineType((String) null); + return bindToRequest(request, template); + } + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Object input) { + return jsonBinder.bindToRequest(request, input); + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiExpectTest.java index aab522bf54..51f9141042 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiExpectTest.java @@ -20,7 +20,6 @@ package org.jclouds.googlecompute.features; import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; -import org.jclouds.googlecompute.options.ListOptions; import org.jclouds.googlecompute.parse.ParseDiskListTest; import org.jclouds.googlecompute.parse.ParseDiskTest; import org.jclouds.googlecompute.parse.ParseOperationTest; @@ -94,8 +93,8 @@ public class DiskApiExpectTest extends BaseGoogleComputeApiExpectTest { TOKEN_RESPONSE, insert, insertDiskResponse).getDiskApiForProject("myproject"); - assertEquals(api.insert("testimage1", URI.create("https://www.googleapis" + - ".com/compute/v1beta13/projects/myproject/zones/us-central1-a"), 1) + assertEquals(api.createInZone("testimage1", 1, URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/zones/us-central1-a")) , new ParseOperationTest().expected()); } diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiLiveTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiLiveTest.java index e8523d56aa..ddf626be3b 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiLiveTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/DiskApiLiveTest.java @@ -60,7 +60,7 @@ public class DiskApiLiveTest extends BaseGoogleComputeApiLiveTest { public void testInsertDisk() { Project project = context.getApi().getProjectApi().get(getUserProject()); zoneUrl = getDefaultZoneUrl(project.getName()); - assertOperationDoneSucessfully(api().insert(DISK_NAME, zoneUrl, sizeGb), TIME_WAIT); + assertOperationDoneSucessfully(api().createInZone(DISK_NAME, sizeGb, zoneUrl), TIME_WAIT); } diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiExpectTest.java new file mode 100644 index 0000000000..b665410236 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiExpectTest.java @@ -0,0 +1,226 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.InstanceTemplate; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; +import org.jclouds.googlecompute.parse.ParseInstanceListTest; +import org.jclouds.googlecompute.parse.ParseInstanceSerialOutputTest; +import org.jclouds.googlecompute.parse.ParseInstanceTest; +import org.jclouds.googlecompute.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import javax.ws.rs.core.MediaType; +import java.net.URI; + +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class InstanceApiExpectTest extends BaseGoogleComputeApiExpectTest { + + public void testGetInstanceResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/instance_get.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.get("test-instance"), + new ParseInstanceTest().expected()); + } + + public void testGetInstanceResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getInstanceApiForProject("myproject"); + + assertNull(api.get("test-instance")); + } + + public void testGetInstanceSerialPortOutput() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance/serialPort") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/instance_serial_port.json")).build(); + + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.getSerialPortOutput("test-instance"), new ParseInstanceSerialOutputTest().expected()); + } + + public void testInsertInstanceResponseIs2xxNoOptions() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1beta13/projects/myproject/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_insert_simple.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertInstanceResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertInstanceResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.createInZone("test-instance", + InstanceTemplate.builder() + .forMachineTypeAndNetwork("n1-standard-1", "default"), + "us-central1-a"), + new ParseOperationTest().expected()); + } + + public void testInsertInstanceResponseIs2xxAllOptions() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1beta13/projects/myproject/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertInstanceResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, insertInstanceResponse).getInstanceApiForProject("myproject"); + + Instance instance = new ParseInstanceTest().expected(); + InstanceTemplate options = new InstanceTemplate.Builder() + .fromInstance(instance) + .network(instance.getNetworkInterfaces().iterator().next().getNetwork()) + .addDisk(InstanceTemplate.PersistentDisk.Mode.READ_WRITE, + URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/disks/test")); + + assertEquals(api.createInZone(instance.getName(), options, "us-central1-a"), + new ParseOperationTest().expected()); + } + + public void testDeleteInstanceResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.delete("test-instance"), + new ParseOperationTest().expected()); + } + + public void testDeleteInstanceResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getInstanceApiForProject("myproject"); + + assertNull(api.delete("test-instance")); + } + + public void testListInstancesResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/instance_list.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseInstanceListTest().expected().toString()); + } + + public void testListInstancesResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getInstanceApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } + +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiLiveTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiLiveTest.java new file mode 100644 index 0000000000..572e99fcb2 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/InstanceApiLiveTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.InstanceTemplate; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiLiveTest; +import org.jclouds.googlecompute.options.ListOptions; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * @author David Alves + */ +public class InstanceApiLiveTest extends BaseGoogleComputeApiLiveTest { + + private static final String INSTANCE_NAME = "instance-api-live-test-instance"; + private static final String DISK_NAME = "instance-live-test-disk"; + private static final int TIME_WAIT = 600; + + private InstanceTemplate instance; + + @BeforeClass(groups = {"integration", "live"}) + public void setupContext() { + super.setupContext(); + instance = InstanceTemplate.builder() + .forMachineTypeAndNetwork(getDefaultMachineTypekUrl(getUserProject()), + getDefaultNetworkUrl(getUserProject())) + .addMetadata("mykey", "myvalue") + .addTag("atag") + .description("a description") + .addDisk(InstanceTemplate.PersistentDisk.Mode.READ_WRITE, getDiskUrl(getUserProject(), DISK_NAME)) + .zone(getDefaultZoneUrl(getUserProject())); + } + + private InstanceApi api() { + return context.getApi().getInstanceApiForProject(getUserProject()); + } + + @Test(groups = "live") + public void testInsertInstance() { + + assertOperationDoneSucessfully(context.getApi().getDiskApiForProject(getUserProject()).createInZone + ("instance-live-test-disk", 1, getDefaultZoneUrl(getUserProject())), TIME_WAIT); + + assertOperationDoneSucessfully(api().createInZone(INSTANCE_NAME, instance, DEFAULT_ZONE_NAME), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertInstance") + public void testInsertInstanceCopy() { + Instance instance = api().get(INSTANCE_NAME); + InstanceTemplate copy = InstanceTemplate.fromInstance(instance); + copy.network(instance.getNetworkInterfaces().iterator().next().getNetwork()); + + assertOperationDoneSucessfully(api().createInZone(INSTANCE_NAME + "-2", copy, DEFAULT_ZONE_NAME), TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testInsertInstance") + public void testGetInstance() { + + Instance instance = api().get(INSTANCE_NAME); + assertNotNull(instance); + assertInstanceEquals(instance, this.instance); + } + + @Test(groups = "live", dependsOnMethods = "testInsertInstance") + public void testListInstance() { + + PagedIterable instances = api().list(new ListOptions.Builder() + .filter("name eq " + INSTANCE_NAME)); + + List instancesAsList = Lists.newArrayList(instances.concat()); + + assertEquals(instancesAsList.size(), 1); + + assertInstanceEquals(Iterables.getOnlyElement(instancesAsList), instance); + + } + + @Test(groups = "live", dependsOnMethods = {"testListInstance", "testInsertInstanceCopy"}) + public void testDeleteInstance() { + + assertOperationDoneSucessfully(api().delete(INSTANCE_NAME), TIME_WAIT); + assertOperationDoneSucessfully(api().delete(INSTANCE_NAME + "-2"), TIME_WAIT); + assertOperationDoneSucessfully(context.getApi().getDiskApiForProject(getUserProject()).delete(DISK_NAME), + TIME_WAIT); + } + + private void assertInstanceEquals(Instance result, InstanceTemplate expected) { + assertEquals(result.getName(), expected.getName()); + assertEquals(result.getTags(), expected.getTags()); + assertEquals(result.getMetadata(), expected.getMetadata()); + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/KernelApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/KernelApiExpectTest.java index d32da3d7b7..cf30bec488 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/KernelApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/KernelApiExpectTest.java @@ -19,8 +19,7 @@ package org.jclouds.googlecompute.features; -import org.jclouds.googlecompute.GoogleComputeApi; -import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; import org.jclouds.googlecompute.parse.ParseKernelListTest; import org.jclouds.googlecompute.parse.ParseKernelTest; import org.jclouds.http.HttpRequest; @@ -36,7 +35,7 @@ import static org.testng.Assert.assertTrue; * @author David Alves */ @Test(groups = "unit") -public class KernelApiExpectTest extends BaseGoogleComputeExpectTest { +public class KernelApiExpectTest extends BaseGoogleComputeApiExpectTest { public void testGetKernelResponseIs2xx() throws Exception { HttpRequest get = HttpRequest diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/MachineTypeApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/MachineTypeApiExpectTest.java index 5818dfb959..7e42475893 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/MachineTypeApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/MachineTypeApiExpectTest.java @@ -19,8 +19,7 @@ package org.jclouds.googlecompute.features; -import org.jclouds.googlecompute.GoogleComputeApi; -import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; import org.jclouds.googlecompute.parse.ParseMachineTypeListTest; import org.jclouds.googlecompute.parse.ParseMachineTypeTest; import org.jclouds.http.HttpRequest; @@ -36,7 +35,7 @@ import static org.testng.Assert.assertTrue; * @author David Alves */ @Test(groups = "unit") -public class MachineTypeApiExpectTest extends BaseGoogleComputeExpectTest { +public class MachineTypeApiExpectTest extends BaseGoogleComputeApiExpectTest { public void testGetMachineTypeResponseIs2xx() throws Exception { HttpRequest get = HttpRequest diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/OperationApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/OperationApiExpectTest.java index bb79d29062..3d4f5999ea 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/OperationApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/OperationApiExpectTest.java @@ -19,8 +19,7 @@ package org.jclouds.googlecompute.features; -import org.jclouds.googlecompute.GoogleComputeApi; -import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; import org.jclouds.googlecompute.options.ListOptions; import org.jclouds.googlecompute.parse.ParseOperationListTest; import org.jclouds.googlecompute.parse.ParseOperationTest; @@ -38,7 +37,7 @@ import static org.testng.Assert.assertTrue; * @author David Alves */ @Test(groups = "unit") -public class OperationApiExpectTest extends BaseGoogleComputeExpectTest { +public class OperationApiExpectTest extends BaseGoogleComputeApiExpectTest { private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" + ".com/compute/v1beta13/projects/myproject/operations"; diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ProjectApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ProjectApiExpectTest.java index 43db7fcaf0..04a829fca4 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ProjectApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ProjectApiExpectTest.java @@ -19,9 +19,8 @@ package org.jclouds.googlecompute.features; -import org.jclouds.googlecompute.GoogleComputeApi; import org.jclouds.googlecompute.GoogleComputeConstants; -import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; import org.jclouds.googlecompute.parse.ParseMetadataTest; import org.jclouds.googlecompute.parse.ParseOperationTest; import org.jclouds.googlecompute.parse.ParseProjectTest; @@ -39,7 +38,7 @@ import static org.testng.Assert.assertNull; * @author David Alves */ @Test(groups = "unit") -public class ProjectApiExpectTest extends BaseGoogleComputeExpectTest { +public class ProjectApiExpectTest extends BaseGoogleComputeApiExpectTest { public static final String PROJECTS_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects"; diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ZoneApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ZoneApiExpectTest.java index 4f6bf65927..ca2bea664c 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ZoneApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/ZoneApiExpectTest.java @@ -19,8 +19,7 @@ package org.jclouds.googlecompute.features; -import org.jclouds.googlecompute.GoogleComputeApi; -import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; import org.jclouds.googlecompute.parse.ParseZoneListTest; import org.jclouds.googlecompute.parse.ParseZoneTest; import org.jclouds.http.HttpRequest; @@ -36,7 +35,7 @@ import static org.testng.Assert.assertTrue; * @author David Alves */ @Test(groups = "unit") -public class ZoneApiExpectTest extends BaseGoogleComputeExpectTest { +public class ZoneApiExpectTest extends BaseGoogleComputeApiExpectTest { public static final String ZONES_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects/google/zones"; diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiExpectTest.java index 906bc5e522..2c552e33b5 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiExpectTest.java @@ -20,9 +20,17 @@ package org.jclouds.googlecompute.internal; import org.jclouds.googlecompute.GoogleComputeApi; +import java.util.Properties; + /** * @author Adrian Cole */ public class BaseGoogleComputeApiExpectTest extends BaseGoogleComputeExpectTest { + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + properties.put("google-compute.identity", "myproject"); + return properties; + } } diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiLiveTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiLiveTest.java index d1b4e49f57..864567618b 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiLiveTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeApiLiveTest.java @@ -18,15 +18,11 @@ */ package org.jclouds.googlecompute.internal; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.jclouds.util.Predicates2.retry; -import static org.testng.Assert.assertEquals; -import static org.testng.AssertJUnit.assertTrue; - -import java.net.URI; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicReference; - +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.reflect.TypeToken; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; import org.jclouds.apis.BaseContextLiveTest; import org.jclouds.googlecompute.GoogleComputeApi; import org.jclouds.googlecompute.GoogleComputeApiMetadata; @@ -36,11 +32,14 @@ import org.jclouds.googlecompute.domain.Operation; import org.jclouds.oauth.v2.OAuthTestUtils; import org.jclouds.rest.RestContext; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.reflect.TypeToken; -import com.google.inject.Key; -import com.google.inject.TypeLiteral; +import java.net.URI; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.util.Predicates2.retry; +import static org.testng.Assert.assertEquals; +import static org.testng.AssertJUnit.assertTrue; /** @@ -123,6 +122,10 @@ public class BaseGoogleComputeApiLiveTest extends BaseContextLiveTest> operationDonePredicate, Operation operation, long maxWaitSeconds) { AtomicReference operationReference = new AtomicReference(operation); diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeExpectTest.java index b731168bc8..5136e84a44 100644 --- a/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeExpectTest.java +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/internal/BaseGoogleComputeExpectTest.java @@ -47,7 +47,7 @@ public class BaseGoogleComputeExpectTest extends BaseRestApiExpectTest { private static final String header = "{\"alg\":\"none\",\"typ\":\"JWT\"}"; private static final String CLAIMS_TEMPLATE = "{" + - "\"iss\":\"identity\"," + + "\"iss\":\"myproject\"," + "\"scope\":\"%s\"," + "\"aud\":\"https://accounts.google.com/o/oauth2/token\"," + "\"exp\":3600," + diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceListTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceListTest.java new file mode 100644 index 0000000000..0d3d046c2a --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceListTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.parse; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Resource; +import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; +import java.net.URI; + +/** + * @author David Alves + */ +public class ParseInstanceListTest extends BaseGoogleComputeParseTest> { + + @Override + public String resource() { + return "/instance_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.INSTANCE_LIST) + .id("projects/myproject/instances") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/instances")) + .items(ImmutableSet.of(new ParseInstanceTest().expected())) + .build(); + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceSerialOutputTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceSerialOutputTest.java new file mode 100644 index 0000000000..c631f91f46 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceSerialOutputTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.parse; + +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +/** + * @author David Alves + */ +public class ParseInstanceSerialOutputTest extends BaseGoogleComputeParseTest { + + @Override + public String resource() { + return "/instance_serial_port.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Instance.SerialPortOutput expected() { + return Instance.SerialPortOutput.builder() + .contents("console output").build(); + } +} \ No newline at end of file diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceTest.java new file mode 100644 index 0000000000..94324b7838 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseInstanceTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.parse; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecompute.domain.Instance; +import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; +import java.net.URI; + +/** + * @author David Alves + */ +public class ParseInstanceTest extends BaseGoogleComputeParseTest { + + @Override + public String resource() { + return "/instance_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Instance expected() { + return Instance.builder() + .id("13051190678907570425") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-11-25T23:48:20.758")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/instances/test-instance")) + .description("desc") + .name("test-instance") + .image(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/google/images/ubuntu-12-04-v20120912")) + .machineType(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/machineTypes/n1" + + "-standard-1")) + .status(Instance.Status.RUNNING) + .zone(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a")) + .addNetworkInterface( + Instance.NetworkInterface.builder() + .name("nic0") + .networkIP("10.240.121.115") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/networks/default")) + .build() + ) + .addDisk( + Instance.PersistentAttachedDisk.builder() + .index(0) + .mode(Instance.PersistentAttachedDisk.Mode.READ_WRITE) + .deviceName("test") + .source(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/disks/test")) + .build() + ) + .addTag("aTag") + .metadata(ImmutableMap.of("aKey", "aValue")) + .addServiceAccount(Instance.ServiceAccount.builder().email("default").addScopes("myscope").build()) + .build(); + } +} diff --git a/labs/google-compute/src/test/resources/disk_insert.json b/labs/google-compute/src/test/resources/disk_insert.json index 32332cf806..82522a7ef8 100644 --- a/labs/google-compute/src/test/resources/disk_insert.json +++ b/labs/google-compute/src/test/resources/disk_insert.json @@ -1 +1 @@ -{"name":"testimage1","zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a","sizeGb":1} \ No newline at end of file +{"name":"testimage1","sizeGb":1,"zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a"} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_add_access_config.json b/labs/google-compute/src/test/resources/instance_add_access_config.json new file mode 100644 index 0000000000..7530a7e768 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_add_access_config.json @@ -0,0 +1,11 @@ +POST https://www.googleapis.com/compute/v1beta13/projects/jclouds-gce/instances/test-instance/addAccessConfig?network_interface=nic0&key={YOUR_API_KEY} + +Content-Type: application/json +Authorization: Bearer ya29.AHES6ZRyNKVHwnMPUvZitAuA8mR8b0lcWh1bMI5UQ5bgsJ4j +X-JavaScript-User-Agent: Google APIs Explorer + +{ + "name": "config1", + "natIP": "10.0.1.1", + "type": "ONE_TO_ONE_NAT" +} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_get.json b/labs/google-compute/src/test/resources/instance_get.json new file mode 100644 index 0000000000..2ffd2c2e43 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_get.json @@ -0,0 +1,50 @@ +{ + "kind": "compute#instance", + "id": "13051190678907570425", + "description": "desc", + "creationTimestamp": "2012-11-25T23:48:20.758", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/instances/test-instance", + "name": "test-instance", + "image": "https://www.googleapis.com/compute/v1beta13/projects/google/images/ubuntu-12-04-v20120912", + "machineType": "https://www.googleapis.com/compute/v1beta13/projects/myproject/machineTypes/n1-standard-1", + "status": "RUNNING", + "zone": "https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a", + "networkInterfaces": [ + { + "kind": "compute#instanceNetworkInterface", + "name": "nic0", + "networkIP": "10.240.121.115", + "network": "https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default" + } + ], + "disks": [ + { + "kind": "compute#instanceDisk", + "type": "PERSISTENT", + "mode": "READ_WRITE", + "deviceName": "test", + "source": "https://www.googleapis.com/compute/v1beta13/projects/myproject/disks/test", + "index": 0 + } + ], + "serviceAccounts": [ + { + "kind": "compute#serviceAccount", + "email": "default", + "scopes": [ + "myscope" + ] + } + ], + "metadata": { + "items": [ + { + "key": "aKey", + "value": "aValue" + } + ] + }, + "tags": [ + "aTag" + ] +} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_insert.json b/labs/google-compute/src/test/resources/instance_insert.json new file mode 100644 index 0000000000..a3946b7005 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_insert.json @@ -0,0 +1 @@ +{"name":"test-instance","description":"desc","machineType":"https://www.googleapis.com/compute/v1beta13/projects/myproject/machineTypes/n1-standard-1","zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a","image":"https://www.googleapis.com/compute/v1beta13/projects/google/images/ubuntu-12-04-v20120912","tags":["aTag"],"serviceAccounts":[{"email":"default","scopes":["myscope"]}],"networkInterfaces":[{"network":"https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default","accessConfigs":[{"name":"external","type":"ONE_TO_ONE_NAT"}]}],"disks":[{"mode":"READ_WRITE","source":"https://www.googleapis.com/compute/v1beta13/projects/myproject/disks/test","type":"PERSISTENT"}],"metadata":{"kind":"compute#metadata","items":[{"key":"aKey","value":"aValue"}]}} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_insert_simple.json b/labs/google-compute/src/test/resources/instance_insert_simple.json new file mode 100644 index 0000000000..b9296b9810 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_insert_simple.json @@ -0,0 +1 @@ +{"name":"test-instance","machineType":"https://www.googleapis.com/compute/v1beta13/projects/myproject/machineTypes/n1-standard-1","zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a","tags":[],"serviceAccounts":[],"networkInterfaces":[{"network":"https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default","accessConfigs":[{"name":"external","type":"ONE_TO_ONE_NAT"}]}]} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_list.json b/labs/google-compute/src/test/resources/instance_list.json new file mode 100644 index 0000000000..06a8697781 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_list.json @@ -0,0 +1,57 @@ +{ + "kind": "compute#instanceList", + "id": "projects/myproject/instances", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/instances", + "items": [ + { + "kind": "compute#instance", + "id": "13051190678907570425", + "description": "desc", + "creationTimestamp": "2012-11-25T23:48:20.758", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/instances/test-instance", + "name": "test-instance", + "image": "https://www.googleapis.com/compute/v1beta13/projects/google/images/ubuntu-12-04-v20120912", + "machineType": "https://www.googleapis.com/compute/v1beta13/projects/myproject/machineTypes/n1-standard-1", + "status": "RUNNING", + "zone": "https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a", + "networkInterfaces": [ + { + "kind": "compute#instanceNetworkInterface", + "name": "nic0", + "networkIP": "10.240.121.115", + "network": "https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default" + } + ], + "disks": [ + { + "kind": "compute#instanceDisk", + "type": "PERSISTENT", + "mode": "READ_WRITE", + "deviceName": "test", + "source": "https://www.googleapis.com/compute/v1beta13/projects/myproject/disks/test", + "index": 0 + } + ], + "serviceAccounts": [ + { + "kind": "compute#serviceAccount", + "email": "default", + "scopes": [ + "myscope" + ] + } + ], + "metadata": { + "items": [ + { + "key": "aKey", + "value": "aValue" + } + ] + }, + "tags": [ + "aTag" + ] + } + ] +} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/instance_serial_port.json b/labs/google-compute/src/test/resources/instance_serial_port.json new file mode 100644 index 0000000000..5813ce9791 --- /dev/null +++ b/labs/google-compute/src/test/resources/instance_serial_port.json @@ -0,0 +1,4 @@ +{ + "kind": "compute#serialPortOutput", + "contents": "console output" +} \ No newline at end of file