Merge pull request #1150 from dralves/gce-instances

gce - instances api
This commit is contained in:
Adrian Cole 2013-01-22 10:25:32 -08:00
commit d074fe19f2
34 changed files with 2924 additions and 60 deletions

View File

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

View File

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

View File

@ -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<InstanceTemplate> {
@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<Instance> {
@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<String> tags, URI image, URI machineType, Status status, String statusMessage,
URI zone, Set<NetworkInterface> networkInterfaces, Metadata metadata,
Set<ServiceAccount> serviceAccounts) {
super(id, creationTimestamp, selfLink, name, description, tags, image, machineType,
status, statusMessage, zone, networkInterfaces, null, metadata, serviceAccounts);
}
}
}
/**
* Parser for Metadata.
*/

View File

@ -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<GoogleComput
.put(DiskApi.class, DiskAsyncApi.class)
.put(FirewallApi.class, FirewallAsyncApi.class)
.put(ImageApi.class, ImageAsyncApi.class)
.put(InstanceApi.class, InstanceAsyncApi.class)
.put(KernelApi.class, KernelAsyncApi.class)
.put(MachineTypeApi.class, MachineTypeAsyncApi.class)
.put(NetworkApi.class, NetworkAsyncApi.class)
@ -108,13 +113,55 @@ public class GoogleComputeRestClientModule extends RestClientModule<GoogleComput
@Provides
@Singleton
@UserProject
public Supplier<String> supplyProject(
@org.jclouds.location.Provider final Supplier<Credentials> creds) {
public Supplier<String> supplyProject(@org.jclouds.location.Provider final Supplier<Credentials> creds) {
return compose(new Function<Credentials, String>() {
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<String, URI> provideMachineTypeNameToURIFunction(final @Provider Supplier<URI> endpoint,
final @UserProject Supplier<String> userProject) {
return new Function<String, URI>() {
@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<String, URI> provideNetworkNameToURIFunction(final @Provider Supplier<URI> endpoint,
final @UserProject Supplier<String> userProject) {
return new Function<String, URI>() {
@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<String, URI> provideZoneNameToURIFunction(final @Provider Supplier<URI> endpoint,
final @UserProject Supplier<String> userProject) {
return new Function<String, URI>() {
@Override
public URI apply(String input) {
return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()).appendPath
("/zones/").appendPath(input).build();
}
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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<String> tags = Sets.newLinkedHashSet();
protected Set<Instance.ServiceAccount> serviceAccounts = Sets.newLinkedHashSet();
protected transient Set<PersistentDisk> disks = Sets.newLinkedHashSet();
protected transient Network network;
protected transient String networkName;
protected transient Map<String, String> 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<String> 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<PersistentDisk> 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<String, String> 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<Instance.ServiceAccount> 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<PersistentDisk> 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<String, String> 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<Instance.ServiceAccount> getServiceAccounts() {
return serviceAccounts;
}
/**
* @see org.jclouds.googlecompute.domain.Instance#getTags()
*/
public Set<String> 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<Instance.NetworkInterface.AccessConfig> accessConfigs;
public Network(URI network, String networkIP, Set<Instance.NetworkInterface.AccessConfig>
accessConfigs) {
this.networkIP = networkIP;
this.network = checkNotNull(network, "network");
this.accessConfigs = accessConfigs;
}
public Set<Instance.NetworkInterface.AccessConfig> 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();
}
}

View File

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

View File

@ -76,7 +76,7 @@ public interface DiskAsyncApi {
ListenableFuture<Disk> 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<Operation> insert(@PayloadParam("name") String diskName,
@PayloadParam("zone") URI zone,
@PayloadParam("sizeGb") int sizeGb);
ListenableFuture<Operation> createInZone(@PayloadParam("name") String diskName,
@PayloadParam("sizeGb") int sizeGb,
@PayloadParam("zone") URI zone);
/**
* @see DiskApi#delete(String)

View File

@ -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.
* <p/>
*
* @author David Alves
* @see InstanceAsyncApi
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/instances/get"/>
*/
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<Instance> listFirstPage();
/**
* @see InstanceApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
public ListPage<Instance> 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<Instance> listAtMarker(@Nullable String marker, @Nullable ListOptions listOptions);
/**
* @see InstanceApi#list(org.jclouds.googlecompute.options.ListOptions)
*/
public PagedIterable<Instance> 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<Instance> 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);
}

View File

@ -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<Instance> 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<Operation> 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<Operation> 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<ListPage<Instance>> listFirstPage();
/**
* @see InstanceApi#listAtMarker(String)
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Path("/instances")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseInstances.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Instance>> 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<ListPage<Instance>> 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<? extends PagedIterable<Instance>> 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<? extends PagedIterable<Instance>> 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<Operation> 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<Operation> 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<Instance.SerialPortOutput> getSerialPortOutput(@PathParam("instance") String instanceName);
}

View File

@ -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<ListPage<Instance>> {
@Inject
public ParseInstances(Json json) {
super(json, new TypeLiteral<ListPage<Instance>>() {});
}
public static class ToPagedIterable extends BaseToPagedIterable<Instance, ToPagedIterable> {
private final GoogleComputeApi api;
@Inject
protected ToPagedIterable(GoogleComputeApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<Instance>> fetchNextPage(final String projectName,
final ListOptions options) {
return new Function<Object, IterableWithMarker<Instance>>() {
@Override
public IterableWithMarker<Instance> apply(Object input) {
return api.getInstanceApiForProject(projectName).listAtMarker(input.toString(), options);
}
};
}
}
}

View File

@ -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<String, URI> machineTypesToURI;
@Inject
@Named("networks")
Function<String, URI> networksToURI;
@Inject
@Named("zones")
Function<String, URI> zonesToURI;
/**
* {@inheritDoc}
*/
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> 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 extends HttpRequest> R bindToRequest(R request, Object input) {
return jsonBinder.bindToRequest(request, input);
}
}

View File

@ -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());
}

View File

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

View File

@ -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());
}
}

View File

@ -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<Instance> instances = api().list(new ListOptions.Builder()
.filter("name eq " + INSTANCE_NAME));
List<Instance> 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());
}
}

View File

@ -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<GoogleComputeApi> {
public class KernelApiExpectTest extends BaseGoogleComputeApiExpectTest {
public void testGetKernelResponseIs2xx() throws Exception {
HttpRequest get = HttpRequest

View File

@ -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<GoogleComputeApi> {
public class MachineTypeApiExpectTest extends BaseGoogleComputeApiExpectTest {
public void testGetMachineTypeResponseIs2xx() throws Exception {
HttpRequest get = HttpRequest

View File

@ -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<GoogleComputeApi> {
public class OperationApiExpectTest extends BaseGoogleComputeApiExpectTest {
private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" +
".com/compute/v1beta13/projects/myproject/operations";

View File

@ -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<GoogleComputeApi> {
public class ProjectApiExpectTest extends BaseGoogleComputeApiExpectTest {
public static final String PROJECTS_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects";

View File

@ -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<GoogleComputeApi> {
public class ZoneApiExpectTest extends BaseGoogleComputeApiExpectTest {
public static final String ZONES_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects/google/zones";

View File

@ -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<GoogleComputeApi> {
@Override
protected Properties setupProperties() {
Properties properties = super.setupProperties();
properties.put("google-compute.identity", "myproject");
return properties;
}
}

View File

@ -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<RestContex
return URI.create(API_URL_PREFIX + project + MACHINE_TYPE_API_URL_SUFFIX + machineType);
}
protected URI getDiskUrl(String project, String diskName) {
return URI.create(API_URL_PREFIX + project + "/disks/" + diskName);
}
protected static Operation waitOperationDone(Predicate<AtomicReference<Operation>> operationDonePredicate,
Operation operation, long maxWaitSeconds) {
AtomicReference<Operation> operationReference = new AtomicReference<Operation>(operation);

View File

@ -47,7 +47,7 @@ public class BaseGoogleComputeExpectTest<T> extends BaseRestApiExpectTest<T> {
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," +

View File

@ -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<ListPage<Instance>> {
@Override
public String resource() {
return "/instance_list.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public ListPage<Instance> expected() {
return ListPage.<Instance>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();
}
}

View File

@ -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<Instance.SerialPortOutput> {
@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();
}
}

View File

@ -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<Instance> {
@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();
}
}

View File

@ -1 +1 @@
{"name":"testimage1","zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a","sizeGb":1}
{"name":"testimage1","sizeGb":1,"zone":"https://www.googleapis.com/compute/v1beta13/projects/myproject/zones/us-central1-a"}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
{
"kind": "compute#serialPortOutput",
"contents": "console output"
}