Merge pull request #1051 from dralves/gce-base

base pr for - jclouds provider for google compute engine
This commit is contained in:
Adrian Cole 2012-12-29 09:12:19 -08:00
commit ff1fb6c1f6
59 changed files with 5317 additions and 0 deletions

View File

@ -0,0 +1,16 @@
Status:
All the private apis are implemented and tested.
Snapshots are disabled because they are also disabled in GCE.
Just missing jcloud.compute glue code (coming soon!)
How to run the live tests:
Pre-requisites:
A Google Api account with Google Compute Engine enabled
The access pk (provided by google in PKCS12 format) in pem format.
running all tests:
mvn clean install -Plive -Dtest.google-compute.identity=<my account>@developer.gserviceaccount.com -Dtest.google-compute.credential=<path to pk.pem>

116
labs/google-compute/pom.xml Normal file
View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds.labs</groupId>
<artifactId>google-compute</artifactId>
<name>jclouds Google Compute Engine provider</name>
<description>jclouds components to access GoogleCompute</description>
<properties>
<jclouds.version>1.6.0-SNAPSHOT</jclouds.version>
<test.google-compute.identity>Email associated with the Google API client_id</test.google-compute.identity>
<test.google-compute.credential>Private key (PKCS12 file) associated with the Google API client_id</test.google-compute.credential>
<test.google-compute.api-version>v1beta13</test.google-compute.api-version>
<test.google-compute.build-version></test.google-compute.build-version>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${jclouds.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds.labs</groupId>
<artifactId>oauth</artifactId>
<version>${project.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.jclouds.labs</groupId>
<artifactId>oauth</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${jclouds.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${jclouds.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${jclouds.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.google-compute.identity>${test.google-compute.identity}</test.google-compute.identity>
<test.google-compute.credential>${test.google-compute.credential}</test.google-compute.credential>
<test.google-compute.api-version>${test.google-compute.api-version}</test.google-compute.api-version>
<test.google-compute.build-version>${test.google-compute.build-version}</test.google-compute.build-version>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,69 @@
/*
* 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;
import com.google.common.annotations.Beta;
import org.jclouds.concurrent.Timeout;
import org.jclouds.googlecompute.features.OperationApi;
import org.jclouds.googlecompute.features.ProjectApi;
import org.jclouds.googlecompute.features.ZoneApi;
import org.jclouds.rest.annotations.Delegate;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import java.util.concurrent.TimeUnit;
/**
* Provides synchronous access to GoogleCompute.
* <p/>
*
* @author David Alves
* @see GoogleComputeAsyncApi
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13">api doc</a>
*/
@Beta
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface GoogleComputeApi {
/**
* Provides synchronous access to Project features
*/
@Delegate
ProjectApi getProjectApi();
/**
* Provides synchronous access to Operation features
*
* @param projectName the name of the project
*/
@Delegate
@Path("/projects/{project}")
OperationApi getOperationApiForProject(@PathParam("project") String projectName);
/**
* Provides synchronous access to Zone features
*
* @param projectName the name of the project
*/
@Delegate
@Path("/projects/{project}")
ZoneApi getZoneApiForProject(@PathParam("project") String projectName);
}

View File

@ -0,0 +1,103 @@
/**
* 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;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import com.google.inject.Module;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.googlecompute.config.GoogleComputeParserModule;
import org.jclouds.googlecompute.config.GoogleComputeRestClientModule;
import org.jclouds.googlecompute.config.OAuthModuleWithoutTypeAdapters;
import org.jclouds.oauth.v2.config.OAuthAuthenticationModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.BaseRestApiMetadata;
import java.net.URI;
import java.util.Properties;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
/**
* Implementation of {@link ApiMetadata} for GoogleCompute v1beta13 API
*
* @author David Alves
*/
public class GoogleComputeApiMetadata extends BaseRestApiMetadata {
public static final TypeToken<RestContext<GoogleComputeApi, GoogleComputeAsyncApi>> CONTEXT_TOKEN = new
TypeToken<RestContext<GoogleComputeApi, GoogleComputeAsyncApi>>() {};
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public GoogleComputeApiMetadata() {
this(new Builder());
}
protected GoogleComputeApiMetadata(Builder builder) {
super(builder);
}
public static Properties defaultProperties() {
Properties properties = BaseRestApiMetadata.defaultProperties();
properties.put("oauth.endpoint", "https://accounts.google.com/o/oauth2/token");
properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token");
properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256");
properties.put(PROPERTY_SESSION_INTERVAL, 3600);
return properties;
}
public static class Builder extends BaseRestApiMetadata.Builder {
protected Builder() {
super(GoogleComputeApi.class, GoogleComputeAsyncApi.class);
id("google-compute")
.name("Google Compute Engine Api")
.identityName("Email associated with the Goole API client_id")
.credentialName("Private key literal associated with the Google API client_id")
.documentation(URI.create("https://developers.google.com/compute/docs"))
.version("v1beta13")
.defaultEndpoint("https://www.googleapis.com/compute/v1beta13")
.defaultProperties(GoogleComputeApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(GoogleComputeRestClientModule.class)
.add(GoogleComputeParserModule.class)
.add(OAuthAuthenticationModule.class)
.add(OAuthModuleWithoutTypeAdapters.class).build());
}
@Override
public GoogleComputeApiMetadata build() {
return new GoogleComputeApiMetadata(this);
}
@Override
public Builder fromApiMetadata(ApiMetadata in) {
super.fromApiMetadata(in);
return this;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* 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;
import com.google.common.annotations.Beta;
import org.jclouds.googlecompute.features.OperationAsyncApi;
import org.jclouds.googlecompute.features.ProjectAsyncApi;
import org.jclouds.googlecompute.features.ZoneAsyncApi;
import org.jclouds.rest.annotations.Delegate;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
* Provides asynchronous access to GoogleCompute via their REST API.
* <p/>
*
* @author David Alves
* @see GoogleComputeApi
*/
@Beta
public interface GoogleComputeAsyncApi {
/**
* Provides asynchronous access to Project features
*/
@Delegate
ProjectAsyncApi getProjectApi();
/**
* Provides asynchronous access to Operation features
*
* @param projectName the name of the project
*/
@Delegate
@Path("/projects/{project}")
OperationAsyncApi getOperationApiForProject(@PathParam("project") String projectName);
/**
* Provides asynchronous access to Zone features
*
* @param projectName the name of the project
*/
@Delegate
@Path("/projects/{project}")
ZoneAsyncApi getZoneApiForProject(@PathParam("project") String projectName);
}

View File

@ -0,0 +1,39 @@
/*
* 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;
/**
* @author David Alves
*/
public interface GoogleComputeConstants {
public static final String COMPUTE_SCOPE = "https://www.googleapis.com/auth/compute";
public static final String COMPUTE_READONLY_SCOPE = "https://www.googleapis.com/auth/compute.readonly";
/**
* TODO storage scopes should be moved to the GCS api
*/
public static final String STORAGE_WRITEONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.write_only";
public static final String STORAGE_READONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.read_only";
}

View File

@ -0,0 +1,191 @@
/*
* 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.config;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.domain.Project;
import org.jclouds.json.config.GsonModule;
import org.jclouds.oauth.v2.domain.ClaimSet;
import org.jclouds.oauth.v2.domain.Header;
import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter;
import org.jclouds.oauth.v2.json.HeaderTypeAdapter;
import javax.inject.Singleton;
import java.beans.ConstructorProperties;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import java.util.Set;
/**
* @author David Alves
*/
public class GoogleComputeParserModule extends AbstractModule {
@Override
protected void configure() {
bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
@Provides
@Singleton
public Map<Type, Object> provideCustomAdapterBindings() {
return ImmutableMap.<Type, Object>of(
Metadata.class, new MetadataTypeAdapter(),
Operation.class, new OperationTypeAdapter(),
Header.class, new HeaderTypeAdapter(),
ClaimSet.class, new ClaimSetTypeAdapter(),
Project.class, new ProjectTypeAdapter()
);
}
/**
* Parser for operations that unwraps errors avoiding an extra intermediate object.
*
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/operations"/>
*/
@Singleton
private static class OperationTypeAdapter implements JsonDeserializer<Operation> {
@Override
public Operation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
JsonParseException {
Operation.Builder operationBuilder = ((Operation) context.deserialize(json,
OperationInternal.class)).toBuilder();
JsonObject error = json.getAsJsonObject().getAsJsonObject("error");
if (error != null) {
JsonArray array = error.getAsJsonArray("errors");
if (array != null) {
for (JsonElement element : array) {
operationBuilder.addError((Operation.Error) context.deserialize(element, Operation.Error.class));
}
}
}
return operationBuilder.build();
}
private static class OperationInternal extends Operation {
@ConstructorProperties({
"id", "creationTimestamp", "selfLink", "name", "description", "targetLink", "targetId",
"clientOperationId", "status", "statusMessage", "user", "progress", "insertTime", "startTime",
"endTime", "httpErrorStatusCode", "httpErrorMessage", "operationType"
})
private OperationInternal(String id, Date creationTimestamp, URI selfLink, String name,
String description, URI targetLink, String targetId, String clientOperationId,
Status status, String statusMessage, String user, int progress, Date insertTime,
Date startTime, Date endTime, int httpErrorStatusCode, String httpErrorMessage,
String operationType) {
super(id, creationTimestamp, selfLink, name, description, targetLink, targetId, clientOperationId,
status, statusMessage, user, progress, insertTime, startTime, endTime, httpErrorStatusCode,
httpErrorMessage, operationType, null);
}
}
}
/**
* Parser for Metadata.
*/
@Singleton
private static class MetadataTypeAdapter implements JsonDeserializer<Metadata>, JsonSerializer<Metadata> {
@Override
public Metadata deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
JsonParseException {
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
JsonObject metadata = json.getAsJsonObject();
JsonArray items = metadata.getAsJsonArray("items");
if (items != null) {
for (JsonElement element : items) {
JsonObject object = element.getAsJsonObject();
builder.put(object.get("key").getAsString(), object.get("value").getAsString());
}
}
return new Metadata(builder.build());
}
@Override
public JsonElement serialize(Metadata src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject metadataObject = new JsonObject();
metadataObject.add("kind", new JsonPrimitive("compute#metadata"));
JsonArray items = new JsonArray();
for (Map.Entry<String, String> entry : src.entrySet()) {
JsonObject object = new JsonObject();
object.addProperty("key", entry.getKey());
object.addProperty("value", entry.getValue());
items.add(object);
}
metadataObject.add("items", items);
return metadataObject;
}
}
public static class Metadata extends ForwardingMap<String, String> {
private final Map<String, String> delegate;
public Metadata(Map<String, String> delegate) {
this.delegate = delegate;
}
@Override
protected Map<String, String> delegate() {
return delegate;
}
}
@Singleton
private static class ProjectTypeAdapter implements JsonDeserializer<Project> {
@Override
public Project deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
JsonParseException {
return Project.builder().fromProject((Project) context.deserialize(json, ProjectInternal.class)).build();
}
private static class ProjectInternal extends Project {
@ConstructorProperties({
"id", "creationTimestamp", "selfLink", "name", "description", "commonInstanceMetadata", "quotas",
"externalIpAddresses"
})
private ProjectInternal(String id, Date creationTimestamp, URI selfLink, String name, String description,
Metadata commonInstanceMetadata, Set<Quota> quotas, Set<String> externalIpAddresses) {
super(id, creationTimestamp, selfLink, name, description, commonInstanceMetadata, quotas,
externalIpAddresses);
}
}
}
}

View File

@ -0,0 +1,91 @@
/**
* 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.config;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
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.googlecompute.GoogleComputeApi;
import org.jclouds.googlecompute.GoogleComputeAsyncApi;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.features.OperationApi;
import org.jclouds.googlecompute.features.OperationAsyncApi;
import org.jclouds.googlecompute.features.ProjectApi;
import org.jclouds.googlecompute.features.ProjectAsyncApi;
import org.jclouds.googlecompute.features.ZoneApi;
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.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.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.rest.config.RestClientModule;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import static com.google.common.base.Preconditions.checkState;
/**
* Configures the GoogleCompute connection.
*
* @author David Alves
*/
@ConfiguresRestClient
public class GoogleComputeRestClientModule extends RestClientModule<GoogleComputeApi, GoogleComputeAsyncApi> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>>builder()
.put(OperationApi.class, OperationAsyncApi.class)
.put(ProjectApi.class, ProjectAsyncApi.class)
.put(ZoneApi.class, ZoneAsyncApi.class)
.build();
public GoogleComputeRestClientModule() {
super(DELEGATE_MAP);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
bind(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {}).to(OperationDonePredicate.class);
super.configure();
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GoogleComputeErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GoogleComputeErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GoogleComputeErrorHandler.class);
}
@Provides
@UserProject
public String provideProject(@Identity String identity) {
checkState(identity.indexOf("@") != 1, "identity should be in project_id@developer.gserviceaccount.com format");
return Iterables.get(Splitter.on("@").split(identity), 0);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.config;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.TypeLiteral;
import org.jclouds.oauth.v2.config.OAuthModule;
import org.jclouds.oauth.v2.domain.OAuthCredentials;
import org.jclouds.oauth.v2.domain.Token;
import org.jclouds.oauth.v2.domain.TokenRequest;
import org.jclouds.oauth.v2.functions.BuildTokenRequest;
import org.jclouds.oauth.v2.functions.FetchToken;
import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier;
import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
* Overrides OAuthModule leaving TypeAdapters bindings out.
* <p/>
* TODO overcome this by using multibindings on GSonModule?
*
* @author David Alves
*/
public class OAuthModuleWithoutTypeAdapters extends OAuthModule {
@Override
protected void configure() {
bind(new TypeLiteral<Function<byte[], byte[]>>() {}).to(SignOrProduceMacForToken.class);
bind(new TypeLiteral<Supplier<OAuthCredentials>>() {}).to(OAuthCredentialsSupplier.class);
bind(new TypeLiteral<Function<GeneratedHttpRequest, TokenRequest>>() {}).to(BuildTokenRequest.class);
bind(new TypeLiteral<Function<TokenRequest, Token>>() {}).to(FetchToken.class);
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.config;
import javax.inject.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Qualifies a property as the user's project id.
*
* @author David Alves
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Qualifier
public @interface UserProject {
}

View File

@ -0,0 +1,179 @@
/*
* 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.base.Optional;
import com.google.common.collect.ImmutableSet;
import org.jclouds.collect.IterableWithMarker;
import java.net.URI;
import java.util.Iterator;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.googlecompute.domain.Resource.Kind;
/**
* The collection returned from any <code>listFirstPage()</code> method.
*
* @author David Alves
*/
public class ListPage<T> extends IterableWithMarker<T> {
private final Kind kind;
private final String id;
private final URI selfLink;
private final String nextPageToken;
private final Iterable<T> items;
protected ListPage(Kind kind, String id, URI selfLink, String nextPageToken, Iterable<T> items) {
this.kind = checkNotNull(kind, "kind of %id", id);
this.id = checkNotNull(id, "id");
this.selfLink = checkNotNull(selfLink, "selfLink of %id", id);
this.nextPageToken = nextPageToken;
this.items = items != null ? ImmutableSet.copyOf(items) : ImmutableSet.<T>of();
}
public Kind getKind() {
return kind;
}
public String getId() {
return id;
}
public URI getSelfLink() {
return selfLink;
}
@Override
public Optional<Object> nextMarker() {
return Optional.<Object>fromNullable(nextPageToken);
}
@Override
public Iterator<T> iterator() {
return items.iterator();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(kind, id);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ListPage that = ListPage.class.cast(obj);
return equal(this.kind, that.kind)
&& equal(this.id, that.id);
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return toStringHelper(this)
.omitNullValues()
.add("kind", kind)
.add("id", id)
.add("selfLink", selfLink)
.add("nextPageToken", nextPageToken)
.add("items", items);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static <T> Builder<T> builder() {
return new Builder<T>();
}
public Builder<T> toBuilder() {
return new Builder<T>().fromPagedList(this);
}
public static final class Builder<T> {
private Kind kind;
private String id;
private URI selfLink;
private String nextPageToken;
private ImmutableSet.Builder<T> items = ImmutableSet.builder();
public Builder<T> kind(Kind kind) {
this.kind = kind;
return this;
}
public Builder<T> id(String id) {
this.id = id;
return this;
}
public Builder<T> selfLink(URI selfLink) {
this.selfLink = selfLink;
return this;
}
public Builder<T> addItem(T item) {
this.items.add(item);
return this;
}
public Builder<T> items(Iterable<T> items) {
this.items.addAll(items);
return this;
}
public Builder<T> nextPageToken(String nextPageToken) {
this.nextPageToken = nextPageToken;
return this;
}
public ListPage<T> build() {
return new ListPage<T>(kind, id, selfLink, nextPageToken, items.build());
}
public Builder<T> fromPagedList(ListPage<T> in) {
return this
.kind(in.getKind())
.id(in.getId())
.selfLink(in.getSelfLink())
.nextPageToken((String) in.nextMarker().orNull())
.items(in);
}
}
}

View File

@ -0,0 +1,513 @@
/*
* 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.ImmutableList;
import org.jclouds.http.HttpResponse;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.Date;
import java.util.List;
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;
/**
* Describes an operation being executed on some Resource
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/operations"/>
*/
@Beta
public class Operation extends Resource {
public static enum Status {
PENDING,
RUNNING,
DONE
}
private final URI targetLink;
private final String targetId;
private final Optional<String> clientOperationId;
private final Status status;
private final Optional<String> statusMessage;
private final String user;
private final Optional<Integer> progress;
private final Date insertTime;
private final Optional<Date> startTime;
private final Optional<Date> endTime;
private final Optional<HttpResponse> httpError;
private final String operationType;
private final List<Error> errors;
protected Operation(String id, Date creationTimestamp, URI selfLink, String name, String description,
URI targetLink, String targetId, String clientOperationId, Status status,
String statusMessage, String user, Integer progress, Date insertTime, Date startTime,
Date endTime, Integer httpErrorStatusCode, String httpErrorMessage, String operationType,
List<Error> errors) {
super(Kind.OPERATION, checkNotNull(id, "id of %s", name), fromNullable(creationTimestamp),
checkNotNull(selfLink, "selfLink of %s", name), checkNotNull(name, "name"), fromNullable(description));
this.targetLink = checkNotNull(targetLink, "targetLink of %s", name);
this.targetId = checkNotNull(targetId, "targetId of %s", name);
this.clientOperationId = fromNullable(clientOperationId);
this.status = checkNotNull(status, "status of %s", name);
this.statusMessage = fromNullable(statusMessage);
this.user = checkNotNull(user, "user of %s", name);
this.progress = fromNullable(progress);
this.insertTime = checkNotNull(insertTime, "insertTime of %s", name);
this.startTime = fromNullable(startTime);
this.endTime = fromNullable(endTime);
this.httpError = httpErrorStatusCode != null ?
Optional.of(HttpResponse.builder()
.statusCode(httpErrorStatusCode)
.message(httpErrorMessage)
.build())
: Optional.<HttpResponse>absent();
this.operationType = checkNotNull(operationType, "insertTime of %s", name);
this.errors = errors == null ? ImmutableList.<Error>of() : ImmutableList.copyOf(errors);
}
/**
* @return URL of the resource the operation is mutating.
*/
public URI getTargetLink() {
return targetLink;
}
/**
* @return unique target id which identifies a particular incarnation of the target.
*/
public String getTargetId() {
return targetId;
}
/**
* @return An optional identifier specified by the client when the mutation was initiated. Must be unique for all
* operation resources in the project.
*/
public Optional<String> getClientOperationId() {
return clientOperationId;
}
/**
* @return Status of the operation. Can be one of the following: PENDING, RUNNING, or DONE.
*/
public Status getStatus() {
return status;
}
/**
* @return An optional textual description of the current status of the operation.
*/
public Optional<String> getStatusMessage() {
return statusMessage;
}
/**
* @return User who requested the operation, for example "user@example.com".
*/
public String getUser() {
return user;
}
/**
* @return an optional progress indicator that ranges from 0 to 100. This should not be used to guess at when the
* operation will be complete. This number should be monotonically increasing as the operation progresses
* (output only).
*/
public Optional<Integer> getProgress() {
return progress;
}
/**
* @return the time that this operation was requested.
*/
public Date getInsertTime() {
return insertTime;
}
/**
* @return the time that this operation was started by the server.
*/
public Optional<Date> getStartTime() {
return startTime;
}
/**
* @return the time that this operation was completed.
*/
public Optional<Date> getEndTime() {
return endTime;
}
/**
* @return if operation fails, the HttpResponse with error status code returned and the message, e.g. NOT_FOUND.
*/
public Optional<HttpResponse> getHttpError() {
return httpError;
}
/**
* @return type of the operation. Examples include insert, update, and delete.
*/
public String getOperationType() {
return operationType;
}
/**
* @return if error occurred during processing of this operation, this field will be populated.
*/
public List<Error> getErrors() {
return errors;
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return super.string()
.omitNullValues()
.add("targetLink", targetLink)
.add("targetId", targetId)
.add("clientOperationId", clientOperationId.orNull())
.add("status", status)
.add("statusMessage", statusMessage.orNull())
.add("user", user)
.add("progress", progress.orNull())
.add("insertTime", insertTime)
.add("startTime", startTime.orNull())
.add("endTime", endTime.orNull())
.add("httpError", httpError.orNull())
.add("operationType", operationType)
.add("errors", errors);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromOperation(this);
}
public static final class Builder extends Resource.Builder<Builder> {
private URI targetLink;
private String targetId;
private String clientOperationId;
private Status status;
private String statusMessage;
private String user;
private Integer progress;
private Date insertTime;
private Date startTime;
private Date endTime;
private Integer httpErrorStatusCode;
private String httpErrorMessage;
private String operationType;
private ImmutableList.Builder<Error> errors = ImmutableList.builder();
/**
* @see Operation#getTargetLink()
*/
public Builder targetLink(URI targetLink) {
this.targetLink = targetLink;
return self();
}
/**
* @see Operation#getTargetId()
*/
public Builder targetId(String targetId) {
this.targetId = targetId;
return self();
}
/**
* @see Operation#getClientOperationId()
*/
public Builder clientOperationId(String clientOperationId) {
this.clientOperationId = clientOperationId;
return self();
}
/**
* @see Operation#getStatus()
*/
public Builder status(Status status) {
this.status = status;
return self();
}
/**
* @see Operation#getStatusMessage()
*/
public Builder statusMessage(String statusMessage) {
this.statusMessage = statusMessage;
return self();
}
/**
* @see Operation#getUser()
*/
public Builder user(String user) {
this.user = user;
return self();
}
/**
* @see Operation#getProgress()
*/
public Builder progress(Integer progress) {
this.progress = progress;
return self();
}
/**
* @see Operation#getInsertTime()
*/
public Builder insertTime(Date insertTime) {
this.insertTime = insertTime;
return self();
}
/**
* @see Operation#getStartTime()
*/
public Builder startTime(Date startTime) {
this.startTime = startTime;
return self();
}
/**
* @see Operation#getEndTime()
*/
public Builder endTime(Date endTime) {
this.endTime = endTime;
return self();
}
/**
* @see Operation#getHttpError()
*/
public Builder httpErrorStatusCode(Integer httpErrorStatusCode) {
this.httpErrorStatusCode = httpErrorStatusCode;
return self();
}
/**
* @see Operation#getHttpError()
*/
public Builder httpErrorMessage(String httpErrorMessage) {
this.httpErrorMessage = httpErrorMessage;
return self();
}
/**
* @see Operation#getOperationType()
*/
public Builder operationType(String operationType) {
this.operationType = operationType;
return self();
}
/**
* @see Operation#getErrors()
*/
public Builder errors(Iterable<Error> errors) {
if (errors != null)
this.errors.addAll(errors);
return self();
}
/**
* @see Operation#getErrors()
*/
public Builder addError(Error error) {
this.errors.add(error);
return self();
}
@Override
protected Builder self() {
return this;
}
public Operation build() {
return new Operation(super.id, super.creationTimestamp, super.selfLink, super.name,
super.description, targetLink, targetId, clientOperationId, status, statusMessage, user, progress,
insertTime, startTime, endTime, httpErrorStatusCode, httpErrorMessage, operationType,
errors.build());
}
public Builder fromOperation(Operation in) {
return super.fromResource(in).targetLink(in.getTargetLink()).targetId(in.getTargetId()).clientOperationId(in
.getClientOperationId().orNull()).status(in.getStatus()).statusMessage(in.getStatusMessage().orNull())
.user(in.getUser()).progress(in.getProgress().get()).insertTime(in.getInsertTime())
.startTime(in.getStartTime().orNull()).endTime(in.getEndTime().orNull())
.httpErrorStatusCode(in.getHttpError().isPresent() ? in.getHttpError().get().getStatusCode() : null)
.httpErrorMessage(in.getHttpError().isPresent() ? in.getHttpError().get().getMessage() : null)
.operationType(in.getOperationType()).errors(in.getErrors());
}
}
/**
* A particular error for an operation including the details.
*/
public static final class Error {
private final String code;
private final Optional<String> location;
private final Optional<String> message;
@ConstructorProperties({
"code", "location", "message"
})
private Error(String code, String location, String message) {
this.code = checkNotNull(code, "code");
this.location = fromNullable(location);
this.message = fromNullable(message);
}
/**
* @return the error type identifier for this error.
*/
public String getCode() {
return code;
}
/**
* @return indicates the field in the request which caused the error..
*/
public Optional<String> getLocation() {
return location;
}
/**
* @return an optional, human-readable error message.
*/
public Optional<String> getMessage() {
return message;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(code, location, message);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Error that = Error.class.cast(obj);
return equal(this.code, that.code)
&& equal(this.location, that.location)
&& equal(this.message, that.message);
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return toStringHelper(this)
.omitNullValues()
.add("code", code)
.add("location", location.orNull())
.add("message", message.orNull());
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromOperationErrorDetail(this);
}
public static final class Builder {
private String code;
private String location;
private String message;
/**
* @see org.jclouds.googlecompute.domain.Operation.Error#getCode()
*/
public Builder code(String code) {
this.code = code;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Operation.Error#getLocation()
*/
public Builder location(String location) {
this.location = location;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Operation.Error#getMessage()
*/
public Builder message(String message) {
this.message = message;
return this;
}
public Error build() {
return new Error(code, location, message);
}
public Builder fromOperationErrorDetail(Error in) {
return new Builder().code(in.getCode()).location(in.getLocation().orNull()).message
(in.getMessage().orNull());
}
}
}
}

View File

@ -0,0 +1,307 @@
/*
* 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.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;
/**
* A Project resource is the root collection and settings resource for all Google Compute Engine resources.
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/projects"/>
*/
@Beta
public class Project extends Resource {
private final Map<String, String> commonInstanceMetadata;
private final Set<Quota> quotas;
private final Set<String> externalIpAddresses;
protected Project(String id, Date creationTimestamp, URI selfLink, String name, String description,
Map<String, String> commonInstanceMetadata, Set<Quota> quotas, Set<String> externalIpAddresses) {
super(Kind.PROJECT, checkNotNull(id, "id of %s", name), fromNullable(creationTimestamp), checkNotNull(selfLink,
"selfLink of %s", name), checkNotNull(name, "name"), fromNullable(description));
this.commonInstanceMetadata = commonInstanceMetadata == null ? ImmutableMap.<String,
String>of() : ImmutableMap.copyOf(commonInstanceMetadata);
this.quotas = quotas == null ? ImmutableSet.<Quota>of() : ImmutableSet.copyOf(quotas);
this.externalIpAddresses = externalIpAddresses == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf
(externalIpAddresses);
}
/**
* @return metadata key/value pairs available to all instances contained in this project.
*/
public Map<String, String> getCommonInstanceMetadata() {
return commonInstanceMetadata;
}
/**
* @return quotas assigned to this project.
*/
public Set<Quota> getQuotas() {
return quotas;
}
/**
* @return internet available IP addresses available for use in this project.
*/
@Nullable
public Set<String> getExternalIpAddresses() {
return externalIpAddresses;
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return super.string()
.add("commonInstanceMetadata", commonInstanceMetadata)
.add("quotas", quotas)
.add("externalIpAddresses", externalIpAddresses);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromProject(this);
}
public static final class Builder extends Resource.Builder<Builder> {
private ImmutableMap.Builder<String, String> commonInstanceMetadata = ImmutableMap.builder();
private ImmutableSet.Builder<Quota> quotas = ImmutableSet.builder();
private ImmutableSet.Builder<String> externalIpAddresses = ImmutableSet.builder();
/**
* @see Project#getCommonInstanceMetadata()
*/
public Builder addCommonInstanceMetadata(String key, String value) {
this.commonInstanceMetadata.put(key, value);
return this;
}
/**
* @see Project#getCommonInstanceMetadata()
*/
public Builder commonInstanceMetadata(Map<String, String> commonInstanceMetadata) {
this.commonInstanceMetadata.putAll(checkNotNull(commonInstanceMetadata, "commonInstanceMetadata"));
return this;
}
/**
* @see Project#getQuotas()
*/
public Builder addQuota(String metric, double usage, double limit) {
this.quotas.add(Quota.builder().metric(metric).usage(usage).limit(limit).build());
return this;
}
/**
* @see Project#getQuotas()
*/
public Builder quotas(Set<Quota> quotas) {
this.quotas.addAll(checkNotNull(quotas));
return this;
}
/**
* @see Project#getExternalIpAddresses()
*/
public Builder addExternalIpAddress(String externalIpAddress) {
this.externalIpAddresses.add(checkNotNull(externalIpAddress, "externalIpAddress"));
return this;
}
/**
* @see Project#getExternalIpAddresses()
*/
public Builder externalIpAddresses(Set<String> externalIpAddresses) {
this.externalIpAddresses.addAll(checkNotNull(externalIpAddresses, "externalIpAddresses"));
return this;
}
@Override
protected Builder self() {
return this;
}
public Project build() {
return new Project(super.id, super.creationTimestamp, super.selfLink, super.name,
super.description, commonInstanceMetadata.build(), quotas.build(), externalIpAddresses.build());
}
public Builder fromProject(Project in) {
return super.fromResource(in).commonInstanceMetadata(in.getCommonInstanceMetadata()).quotas(in.getQuotas())
.externalIpAddresses(in.getExternalIpAddresses());
}
}
/**
* Quotas assigned to a given project
*
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/projects#resource"/>
*/
public static final class Quota {
private String metric;
private double usage;
private double limit;
@ConstructorProperties({
"metric", "usage", "limit"
})
protected Quota(String metric, Double usage, Double limit) {
this.metric = checkNotNull(metric, "metric");
this.usage = checkNotNull(usage, "usage");
this.limit = checkNotNull(limit, "limit");
}
/**
* @return name of the quota metric.
*/
public String getMetric() {
return metric;
}
/**
* @return current usage of this metric.
*/
public Double getUsage() {
return usage;
}
/**
* @return quota limit for this metric.
*/
public Double getLimit() {
return limit;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(metric);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Quota that = Quota.class.cast(obj);
return equal(this.metric, that.metric);
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return toStringHelper(this)
.omitNullValues()
.add("metric", metric)
.add("usage", usage)
.add("limit", limit);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromQuota(this);
}
public static class Builder {
private String metric;
private Double usage;
private Double limit;
/**
* @see org.jclouds.googlecompute.domain.Project.Quota#getMetric()
*/
public Builder metric(String metric) {
this.metric = checkNotNull(metric, "metric");
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Project.Quota#getUsage()
*/
public Builder usage(Double usage) {
this.usage = usage;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Project.Quota#getLimit()
*/
public Builder limit(Double limit) {
this.limit = limit;
return this;
}
public Quota build() {
return new Quota(metric, usage, limit);
}
public Builder fromQuota(Quota quota) {
return new Builder().metric(quota.getMetric()).usage(quota.getUsage()).limit(quota.getLimit());
}
}
}
}

View File

@ -0,0 +1,283 @@
/*
* 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.CaseFormat;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import org.jclouds.javax.annotation.Nullable;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.Date;
import static com.google.common.base.Objects.ToStringHelper;
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;
/**
* Base class for Google Compute Engine resources.
*
* @author David Alves
*/
@Beta
public class Resource {
public enum Kind {
DISK,
DISK_LIST,
FIREWALL,
FIREWALL_LIST,
IMAGE,
IMAGE_LIST,
OPERATION,
OPERATION_LIST,
INSTANCE,
INSTANCE_LIST,
KERNEL,
KERNEL_LIST,
MACHINE_TYPE,
MACHINE_TYPE_LIST,
PROJECT,
NETWORK,
NETWORK_LIST,
ZONE,
ZONE_LIST;
public String value() {
return Joiner.on("#").join("compute", CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name()));
}
@Override
public String toString() {
return value();
}
public static Kind fromValue(String kind) {
return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat
.UPPER_UNDERSCORE,
Iterables.getLast(Splitter.on("#").split(checkNotNull(kind,
"kind")))));
}
}
protected final Kind kind;
protected final String id;
protected final Optional<Date> creationTimestamp;
protected final URI selfLink;
protected final String name;
protected final Optional<String> description;
@ConstructorProperties({
"kind", "id", "creationTimestamp", "selfLink", "name", "description"
})
protected Resource(Kind kind, String id, Optional<Date> creationTimestamp, URI selfLink, String name,
Optional<String> description) {
this.kind = checkNotNull(kind, "kind");
this.id = id;
this.creationTimestamp = creationTimestamp;
this.selfLink = selfLink;
this.name = checkNotNull(name, "name");
this.description = description;
}
/**
* @return the Type of the resource
*/
public Kind getKind() {
return kind;
}
/**
* @return unique identifier for the resource; defined by the server.
*/
public String getId() {
return id;
}
/**
* @return creation timestamp in RFC3339 text format.
*/
public Optional<Date> getCreationTimestamp() {
return creationTimestamp;
}
/**
* @return server defined URL for the resource.
*/
public URI getSelfLink() {
return selfLink;
}
/**
* @return name of the resource.
*/
public String getName() {
return name;
}
/**
* @return an optional textual description of the resource.
*/
@Nullable
public Optional<String> getDescription() {
return description;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(kind, id, name);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Resource that = Resource.class.cast(obj);
return equal(this.kind, that.kind)
&& equal(this.id, that.id)
&& equal(this.name, that.name);
}
/**
* {@inheritDoc}
*/
protected ToStringHelper string() {
return toStringHelper(this)
.omitNullValues()
.add("kind", kind)
.add("id", id)
.add("name", name)
.add("creationTimestamp", creationTimestamp.orNull())
.add("selfLink", selfLink)
.add("name", name)
.add("description", description.orNull());
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromResource(this);
}
public abstract static class Builder<T extends Builder<T>> {
protected abstract T self();
protected Kind kind;
protected String id;
protected Date creationTimestamp;
protected URI selfLink;
protected String name;
protected String description;
/**
* @see Resource#getKind()
*/
protected T kind(Kind kind) {
this.kind = kind;
return self();
}
/**
* @see Resource#getId()
*/
public T id(String id) {
this.id = id;
return self();
}
/**
* @see Resource#getCreationTimestamp()
*/
public T creationTimestamp(Date creationTimestamp) {
this.creationTimestamp = creationTimestamp;
return self();
}
/**
* @see Resource#getSelfLink()
*/
public T selfLink(URI selfLink) {
this.selfLink = selfLink;
return self();
}
/**
* @see Resource#getName()
*/
public T name(String name) {
this.name = name;
return self();
}
/**
* @see Resource#getDescription()
*/
public T description(String description) {
this.description = description;
return self();
}
public Resource build() {
return new Resource(kind, id, fromNullable(creationTimestamp), selfLink, name,
fromNullable(description));
}
public T fromResource(Resource in) {
return this
.kind(in.getKind())
.id(in.getId())
.creationTimestamp(in.getCreationTimestamp().orNull())
.selfLink(in.getSelfLink())
.name(in.getName())
.description(in.getDescription().orNull());
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
}

View File

@ -0,0 +1,338 @@
/*
* 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.ImmutableSet;
import org.jclouds.javax.annotation.Nullable;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.Date;
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 zone resource.
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/zones"/>
*/
@Beta
public final class Zone extends Resource {
public enum Status {
UP,
DOWN
}
private final Status status;
private final Set<MaintenanceWindow> maintenanceWindows;
private final Set<String> availableMachineTypes;
@ConstructorProperties({
"id", "creationTimestamp", "selfLink", "name", "description", "status", "maintenanceWindows",
"availableMachineTypes"
})
private Zone(String id, Date creationTimestamp, URI selfLink, String name, String description,
Status status, Set<MaintenanceWindow> maintenanceWindows, Set<String> availableMachineTypes) {
super(Kind.ZONE, checkNotNull(id, "id of %name", name), fromNullable(creationTimestamp),
checkNotNull(selfLink, "selfLink of %name", name), checkNotNull(name, "name"), fromNullable(description));
this.status = checkNotNull(status, "status of %name", name);
this.maintenanceWindows = maintenanceWindows == null ? ImmutableSet.<MaintenanceWindow>of() : ImmutableSet
.copyOf(maintenanceWindows);
this.availableMachineTypes = availableMachineTypes == null ? ImmutableSet.<String>of() : ImmutableSet
.copyOf(availableMachineTypes);
}
/**
* @return Status of the zone. "UP" or "DOWN".
*/
public Status getStatus() {
return status;
}
/**
* @return scheduled maintenance windows for the zone. When the zone is in a maintenance window,
* all resources which reside in the zone will be unavailable.
*/
public Set<MaintenanceWindow> getMaintenanceWindows() {
return maintenanceWindows;
}
/**
* @return the machine types that can be used in this zone.
*/
@Nullable
public Set<String> getAvailableMachineTypes() {
return availableMachineTypes;
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return super.string()
.add("status", status)
.add("maintenanceWindows", maintenanceWindows)
.add("availableMachineTypes", availableMachineTypes);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromZone(this);
}
public static final class Builder extends Resource.Builder<Builder> {
private Status status;
private ImmutableSet.Builder<MaintenanceWindow> maintenanceWindows = ImmutableSet.builder();
private ImmutableSet.Builder<String> availableMachineTypes = ImmutableSet.builder();
/**
* @see Zone#getStatus()
*/
public Builder status(Status status) {
this.status = status;
return this;
}
/**
* @see Zone#getMaintenanceWindows()
*/
public Builder addMaintenanceWindow(MaintenanceWindow maintenanceWindow) {
this.maintenanceWindows.add(checkNotNull(maintenanceWindow, "maintenanceWindow"));
return this;
}
/**
* @see Zone#getMaintenanceWindows()
*/
public Builder maintenanceWindows(Set<MaintenanceWindow> maintenanceWindows) {
this.maintenanceWindows.addAll(checkNotNull(maintenanceWindows, "maintenanceWindows"));
return this;
}
/**
* @see Zone#getAvailableMachineTypes()
*/
public Builder addAvailableMachineType(String availableMachineType) {
this.availableMachineTypes.add(checkNotNull(availableMachineType, "availableMachineType"));
return this;
}
/**
* @see Zone#getAvailableMachineTypes()
*/
public Builder availableMachineTypes(Set<String> availableMachineTypes) {
this.availableMachineTypes.addAll(checkNotNull(availableMachineTypes, "availableMachineTypes"));
return this;
}
@Override
protected Builder self() {
return this;
}
public Zone build() {
return new Zone(super.id, super.creationTimestamp, super.selfLink, super.name,
super.description, status, maintenanceWindows.build(), availableMachineTypes.build());
}
public Builder fromZone(Zone in) {
return super.fromResource(in)
.status(in.getStatus())
.maintenanceWindows(in.getMaintenanceWindows())
.availableMachineTypes(in.getAvailableMachineTypes());
}
}
/**
* Scheduled maintenance windows for the zone. When the zone is in a maintenance window,
* all resources which reside in the zone will be unavailable.
*
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/zones"/>
*/
public static final class MaintenanceWindow {
private final String name;
private final Optional<String> description;
private final Date beginTime;
private final Date endTime;
@ConstructorProperties({
"name", "description", "beginTime", "endTime"
})
private MaintenanceWindow(String name, String description, Date beginTime, Date endTime) {
this.name = checkNotNull(name, "name");
this.description = fromNullable(description);
this.beginTime = checkNotNull(beginTime, "beginTime of %name", name);
this.endTime = checkNotNull(endTime, "endTime of %name", name);
}
/**
* @return name of the maintenance window.
*/
public String getName() {
return name;
}
/**
* @return textual description of the maintenance window.
*/
public Optional<String> getDescription() {
return description;
}
/**
* @return begin time of the maintenance window.
*/
public Date getBeginTime() {
return beginTime;
}
/**
* @return end time of the maintenance window.
*/
public Date getEndTime() {
return endTime;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(name, description, beginTime, endTime);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MaintenanceWindow that = MaintenanceWindow.class.cast(obj);
return equal(this.name, that.name)
&& equal(this.beginTime, that.beginTime)
&& equal(this.endTime, that.endTime);
}
/**
* {@inheritDoc}
*/
protected Objects.ToStringHelper string() {
return toStringHelper(this)
.omitNullValues()
.add("name", name)
.add("description", description.orNull())
.add("beginTime", beginTime)
.add("endTime", endTime);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return string().toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromZoneMaintenanceWindow(this);
}
public static final class Builder {
private String name;
private String description;
private Date beginTime;
private Date endTime;
/**
* @see org.jclouds.googlecompute.domain.Zone.MaintenanceWindow#getName()
*/
public Builder name(String name) {
this.name = name;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Zone.MaintenanceWindow#getDescription()
*/
public Builder description(String description) {
this.description = description;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Zone.MaintenanceWindow#getBeginTime()
*/
public Builder beginTime(Date beginTime) {
this.beginTime = beginTime;
return this;
}
/**
* @see org.jclouds.googlecompute.domain.Zone.MaintenanceWindow#getEndTime()
*/
public Builder endTime(Date endTime) {
this.endTime = endTime;
return this;
}
public MaintenanceWindow build() {
return new MaintenanceWindow(name, description, beginTime, endTime);
}
public Builder fromZoneMaintenanceWindow(MaintenanceWindow in) {
return new Builder()
.name(in.getName())
.description(in.getDescription().orNull())
.beginTime(in.getBeginTime())
.endTime(in.getEndTime());
}
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.concurrent.Timeout;
import org.jclouds.googlecompute.domain.ListPage;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.options.ListOptions;
import org.jclouds.javax.annotation.Nullable;
import java.util.concurrent.TimeUnit;
/**
* Provides synchronous access to Operations via their REST API.
* <p/>
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/operations"/>
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface OperationApi {
/**
* Retrieves the specified operation resource.
*
* @param operationName name of the operation resource to return.
* @return If successful, this method returns an Operation resource
*/
public Operation get(String operationName);
/**
* Deletes the specified operation resource.
*
* @param operationName name of the operation resource to delete.
*/
public void delete(String operationName);
/**
* @see OperationApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
public ListPage<Operation> listFirstPage();
/**
* @see OperationApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
public ListPage<Operation> listAtMarker(@Nullable String marker);
/**
* Retrieves the listFirstPage of operation resources contained within the specified project.
* By default the listFirstPage 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, starting at marker
* @see ListOptions
* @see org.jclouds.googlecompute.domain.ListPage
*/
public ListPage<Operation> listAtMarker(@Nullable String marker, ListOptions listOptions);
/**
* @see OperationApi#list(org.jclouds.googlecompute.options.ListOptions)
*/
public PagedIterable<Operation> list();
/**
* A paged version of OperationApi#listFirstPage()
*
* @return a Paged, Fluent Iterable that is able to fetch additional pages when required
* @see PagedIterable
* @see OperationApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
public PagedIterable<Operation> list(ListOptions listOptions);
}

View File

@ -0,0 +1,138 @@
/*
* 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.ListPage;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.functions.internal.ParseOperations;
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.Fallback;
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 javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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 Operations via their REST API.
*
* @author David Alves
* @see OperationApi
*/
@SkipEncoding({'/', '='})
@RequestFilters(OAuthAuthenticator.class)
public interface OperationAsyncApi {
/**
* @see OperationApi#get(String)
*/
@GET
@Path("/operations/{operation}")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@Fallback(NullOnNotFoundOr404.class)
ListenableFuture<Operation> get(@PathParam("operation") String operationName);
/**
* @see OperationApi#delete(String)
*/
@DELETE
@Path("/operations/{operation}")
@OAuthScopes(COMPUTE_SCOPE)
@Fallback(NullOnNotFoundOr404.class)
ListenableFuture<Void> delete(@PathParam("operation") String operationName);
/**
* @see OperationApi#listFirstPage()
*/
@GET
@Path("/operations")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@ResponseParser(ParseOperations.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Operation>> listFirstPage();
/**
* @see OperationApi#listAtMarker(String)
*/
@GET
@Path("/operations")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@ResponseParser(ParseOperations.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Operation>> listAtMarker(@QueryParam("pageToken") @Nullable String marker);
/**
* @see OperationApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
@GET
@Path("/operations")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@ResponseParser(ParseOperations.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Operation>> listAtMarker(@QueryParam("pageToken") @Nullable String marker,
ListOptions listOptions);
/**
* @see OperationApi#list()
*/
@GET
@Path("/operations")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@ResponseParser(ParseOperations.class)
@Transform(ParseOperations.ToPagedIterable.class)
@Fallback(EmptyPagedIterableOnNotFoundOr404.class)
ListenableFuture<? extends PagedIterable<Operation>> list();
/**
* @see OperationApi#list(org.jclouds.googlecompute.options.ListOptions)
*/
@GET
@Path("/operations")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@ResponseParser(ParseOperations.class)
@Transform(ParseOperations.ToPagedIterable.class)
@Fallback(EmptyPagedIterableOnNotFoundOr404.class)
ListenableFuture<? extends PagedIterable<Operation>> list(ListOptions listOptions);
}

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.features;
import org.jclouds.concurrent.Timeout;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.domain.Project;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Provides synchronous access to Projects via their REST API.
* <p/>
*
* @author David Alves
* @see ProjectAsyncApi
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/projects"/>
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface ProjectApi {
/**
* Returns the specified project resource.
*
* @param projectName name of the project to return
* @return if successful, this method returns a Project resource
*/
Project get(String projectName);
/**
* Sets metadata common to all instances within the specified project using the data included in the request.
* <p/>
* NOTE: This *sets* metadata items on the project (vs *adding* items to metadata),
* if there are pre-existing metadata items that must be kept these must be fetched first and then re-set on the
* new Metadata, e.g.
* <pre><tt>
* Metadata.Builder current = projectApi.get("myProject").getCommonInstanceMetadata().toBuilder();
* current.addItem("newItem","newItemValue");
* projectApi.setCommonInstanceMetadata(current.build());
* </tt></pre>
*
* @param projectName name of the project to return
* @param commonInstanceMetadata the metadata to set
* @return an Operations resource. To check on the status of an operation, poll the Operations resource returned
* to you, and look for the status field.
*/
Operation setCommonInstanceMetadata(String projectName, Map<String, String> commonInstanceMetadata);
}

View File

@ -0,0 +1,78 @@
/*
* 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.googlecompute.domain.Operation;
import org.jclouds.googlecompute.domain.Project;
import org.jclouds.googlecompute.handlers.MetadataBinder;
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.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
import javax.ws.rs.Consumes;
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.core.MediaType;
import java.util.Map;
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 Projects via their REST API.
*
* @author David Alves
* @see ProjectApi
*/
@SkipEncoding({'/', '='})
@RequestFilters(OAuthAuthenticator.class)
public interface ProjectAsyncApi {
/**
* @see ProjectApi#get(String)
*/
@GET
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@Fallback(NullOnNotFoundOr404.class)
@Path("/projects/{project}")
ListenableFuture<Project> get(@PathParam("project") String projectName);
/**
* @see ProjectApi#setCommonInstanceMetadata(String, java.util.Map)
*/
@POST
@Path("/projects/{project}/setCommonInstanceMetadata")
@OAuthScopes(COMPUTE_SCOPE)
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
ListenableFuture<Operation> setCommonInstanceMetadata(@PathParam("project") String projectName,
@BinderParam(MetadataBinder.class)
Map<String, String> commonInstanceMetadata);
}

View File

@ -0,0 +1,86 @@
/*
* 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.concurrent.Timeout;
import org.jclouds.googlecompute.domain.ListPage;
import org.jclouds.googlecompute.domain.Zone;
import org.jclouds.googlecompute.options.ListOptions;
import org.jclouds.javax.annotation.Nullable;
import java.util.concurrent.TimeUnit;
/**
* Provides synchronous access to Zones via their REST API.
* <p/>
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/zones"/>
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface ZoneApi {
/**
* Returns the specified zone resource
*
* @param zoneName name of the zone resource to return.
* @return If successful, this method returns a Zone resource
*/
Zone get(String zoneName);
/**
* @see ZoneApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
ListPage<Zone> listFirstPage();
/**
* @see ZoneApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
ListPage<Zone> listAtMarker(@Nullable String marker);
/**
* Retrieves the listFirstPage of zone resources available to the specified project.
* By default the listFirstPage 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 listFirstPage
* @see ListOptions
* @see ListPage
*/
ListPage<Zone> listAtMarker(@Nullable String marker, ListOptions listOptions);
/**
* @see ZoneApi#list(org.jclouds.googlecompute.options.ListOptions)
*/
PagedIterable<Zone> list();
/**
* A paged version of ZoneApi#listFirstPage()
*
* @return a Paged, Fluent Iterable that is able to fetch additional pages when required
* @see ZoneApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
* @see PagedIterable
*/
PagedIterable<Zone> list(ListOptions listOptions);
}

View File

@ -0,0 +1,118 @@
/*
* 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.ListPage;
import org.jclouds.googlecompute.domain.Zone;
import org.jclouds.googlecompute.functions.internal.ParseZones;
import org.jclouds.googlecompute.options.ListOptions;
import org.jclouds.oauth.v2.config.OAuthScopes;
import org.jclouds.oauth.v2.filters.OAuthAuthenticator;
import org.jclouds.rest.annotations.Fallback;
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 javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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;
/**
* Provides asynchronous access to Zones via their REST API.
*
* @author David Alves
* @see ZoneApi
*/
@SkipEncoding({'/', '='})
@RequestFilters(OAuthAuthenticator.class)
@Consumes(MediaType.APPLICATION_JSON)
public interface ZoneAsyncApi {
/**
* @see ZoneApi#get(String)
*/
@GET
@Path("/zones/{zone}")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@Fallback(NullOnNotFoundOr404.class)
ListenableFuture<Zone> get(@PathParam("zone") String zoneName);
/**
* @see ZoneApi#listFirstPage()
*/
@GET
@Path("/zones")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseZones.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Zone>> listFirstPage();
/**
* @see ZoneApi#listAtMarker(String)
*/
@GET
@Path("/zones")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseZones.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Zone>> listAtMarker(String marker);
/**
* @see ZoneApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions)
*/
@GET
@Path("/zones")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseZones.class)
@Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class)
ListenableFuture<ListPage<Zone>> listAtMarker(String marker, ListOptions listOptions);
/**
* @see ZoneApi#list()
*/
@GET
@Path("/zones")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseZones.class)
@Transform(ParseZones.ToPagedIterable.class)
@Fallback(EmptyPagedIterableOnNotFoundOr404.class)
ListenableFuture<? extends PagedIterable<Zone>> list();
/**
* @see ZoneApi#list(org.jclouds.googlecompute.options.ListOptions)
*/
@GET
@Path("/zones")
@OAuthScopes(COMPUTE_READONLY_SCOPE)
@ResponseParser(ParseZones.class)
@Transform(ParseZones.ToPagedIterable.class)
@Fallback(EmptyPagedIterableOnNotFoundOr404.class)
ListenableFuture<? extends PagedIterable<Zone>> list(ListOptions listOptions);
}

View File

@ -0,0 +1,75 @@
/*
* 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.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.collect.PagedIterables;
import org.jclouds.googlecompute.domain.ListPage;
import org.jclouds.googlecompute.options.ListOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import java.util.Arrays;
/**
* @author Adrian Cole
*/
@Beta
public abstract class BaseToPagedIterable<T, I extends BaseToPagedIterable<T, I>> implements
Function<ListPage<T>, PagedIterable<T>>, InvocationContext<I> {
private GeneratedHttpRequest request;
@Override
public PagedIterable<T> apply(ListPage<T> input) {
if (input.nextMarker() == null)
return PagedIterables.of(input);
Optional<Object> project = Iterables.tryFind(Arrays.asList(request.getCaller().get().getArgs()),
Predicates.instanceOf(String.class));
Optional<Object> listOptions = Iterables.tryFind(request.getArgs(),
Predicates.instanceOf(ListOptions.class));
assert project.isPresent() : String.format("programming error, method %s should have a string param for the " +
"project", request.getCaller().get().getMethod());
return PagedIterables.advance(input, fetchNextPage(project.get().toString(), (String) input.nextMarker().orNull(),
(ListOptions) listOptions.orNull()));
}
protected abstract Function<Object, IterableWithMarker<T>> fetchNextPage(String projectName, String marker,
ListOptions listOptions);
@SuppressWarnings("unchecked")
@Override
public I setContext(HttpRequest request) {
this.request = GeneratedHttpRequest.class.cast(request);
return (I) this;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.ListPage;
import org.jclouds.googlecompute.domain.Operation;
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 ParseOperations extends ParseJson<ListPage<Operation>> {
@Inject
public ParseOperations(Json json) {
super(json, new TypeLiteral<ListPage<Operation>>() {});
}
public static class ToPagedIterable extends BaseToPagedIterable<Operation, ToPagedIterable> {
private final GoogleComputeApi api;
@Inject
protected ToPagedIterable(GoogleComputeApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<Operation>> fetchNextPage(final String projectName,
final String marker,
final ListOptions options) {
return new Function<Object, IterableWithMarker<Operation>>() {
@Override
public IterableWithMarker<Operation> apply(Object input) {
return api.getOperationApiForProject(projectName).listAtMarker(marker, options);
}
};
}
}
}

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.ListPage;
import org.jclouds.googlecompute.domain.Zone;
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 ParseZones extends ParseJson<ListPage<Zone>> {
@Inject
public ParseZones(Json json) {
super(json, new TypeLiteral<ListPage<Zone>>() {});
}
public static class ToPagedIterable extends BaseToPagedIterable<Zone, ToPagedIterable> {
private final GoogleComputeApi api;
@Inject
protected ToPagedIterable(GoogleComputeApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<Zone>> fetchNextPage(final String projectName, final String marker,
final ListOptions options) {
return new Function<Object, IterableWithMarker<Zone>>() {
@Override
public IterableWithMarker<Zone> apply(Object input) {
return api.getZoneApiForProject(projectName).listAtMarker(marker, options);
}
};
}
}
}

View File

@ -0,0 +1,66 @@
/**
* 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 org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import javax.inject.Singleton;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
/**
* This will parse and set an appropriate exception on the command object.
*
* @author Adrian Cole
*/
@Singleton
public class GoogleComputeErrorHandler implements HttpErrorHandler {
public void handleError(HttpCommand command, HttpResponse response) {
// it is important to always read fully and close streams
byte[] data = closeClientButKeepContentStream(response);
String message = data != null ? new String(data) : null;
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 400:
break;
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
case 409:
exception = new IllegalStateException(message, exception);
break;
}
command.setException(exception);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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 org.jclouds.googlecompute.config.GoogleComputeParserModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.binders.BindToJsonPayload;
import javax.inject.Inject;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author David Alves
*/
public class MetadataBinder implements Binder {
@Inject
private BindToJsonPayload jsonBinder;
@Override
@SuppressWarnings("unchecked")
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
Map<String, String> metadataEntries = (Map<String, String>) checkNotNull(input, "input metadata");
return jsonBinder.bindToRequest(request, new GoogleComputeParserModule.Metadata(metadataEntries));
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Allows to optionally specify a filter, max results and a page token for <code>listFirstPage()</code> REST methods.
*
* @author David Alves
* @see <a href="https://developers.google.com/compute/docs/reference/v1beta13/operations/listFirstPage"/>
*/
public class ListOptions extends BaseHttpRequestOptions {
/**
* Optional. Filter expression for filtering listed resources, in the form filter={expression}. Your {expression}
* must contain the following:
* <p/>
* {@code <field_name> <comparison_string> <literal_string>}
* <ul>
* <li>{@code <field_name>}: The name of the field you want to compare. The field name must be valid for the
* type of resource being filtered. Only atomic field types are supported (string, number,
* boolean). Array and object fields are not currently supported.</li>
* <li>{@code <comparison_string>}: The comparison string, either eq (equals) or ne (not equals).</li>
* <li>{@code <literal_string>}: The literal string value to filter to. The literal value must be valid
* for the type of field (string, number, boolean). For string fields, the literal value is interpreted as a
* regular expression using RE2 syntax. The literal value must match the entire field. For example,
* when filtering instances, name eq my_instance won't work, but name eq .*my_instance will work.</li>
* </ul>
* <p/>
* For example:
* <p/>
* {@code filter=status ne RUNNING}
* <p/>
* The above filter returns only results whose status field does not equal RUNNING. You can also enclose your
* literal string in single, double, or no quotes. For example, all three of the following would be valid
* expressions:
* <p/>
* {@code filter=status ne "RUNNING"}<br/>
* {@code filter=status ne 'RUNNING'}<br/>
* {@code filter=status ne RUNNING}<br/>
* <p/>
* Complex regular expressions can also be used, like the following:
* {@code name eq '."my_instance_[0-9]+'}
*/
public ListOptions filter(String filter) {
this.queryParameters.put("filter", checkNotNull(filter, "filter"));
return this;
}
/**
* Sets Maximum count of results to be returned. Maximum and default value is 100. Acceptable values are 0 to
* 100, inclusive. (Default: 100)
*/
public ListOptions maxResults(Integer maxResults) {
this.queryParameters.put("maxResults", checkNotNull(maxResults, "maxResults") + "");
return this;
}
public static class Builder {
/**
* @see ListOptions#filter(String)
*/
public ListOptions filter(String filter) {
return new ListOptions().filter(filter);
}
/**
* @see ListOptions#maxResults(Integer)
*/
public ListOptions maxResults(Integer maxResults) {
return new ListOptions().maxResults(maxResults);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.predicates;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
import org.jclouds.googlecompute.GoogleComputeApi;
import org.jclouds.googlecompute.config.UserProject;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.features.OperationApi;
import java.util.concurrent.atomic.AtomicReference;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tests that an Operation is done, returning the completed Operation when it is.
*
* @author David Alves
*/
public class OperationDonePredicate implements Predicate<AtomicReference<Operation>> {
private OperationApi api;
@Inject
OperationDonePredicate(GoogleComputeApi api, @UserProject String project) {
this.api = api.getOperationApiForProject(project);
}
@Override
public boolean apply(AtomicReference<Operation> input) {
checkNotNull(input, "input");
Operation current = api.get(input.get().getName());
switch (current.getStatus()) {
case DONE:
input.set(current);
return true;
case PENDING:
case RUNNING:
default:
return false;
}
}
}

View File

@ -0,0 +1 @@
org.jclouds.googlecompute.GoogleComputeApiMetadata

View File

@ -0,0 +1,41 @@
/**
* 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;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import org.jclouds.View;
import org.jclouds.apis.internal.BaseApiMetadataTest;
import org.testng.annotations.Test;
/**
* Tests that GoogleComputeApiMetadata is properly registered in ServiceLoader
* <p/>
* <pre>
* META-INF/services/org.jclouds.apis.ApiMetadata
* </pre>
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "GoogleComputeApiMetadataTest")
public class GoogleComputeApiMetadataTest extends BaseApiMetadataTest {
public GoogleComputeApiMetadataTest() {
super(new GoogleComputeApiMetadata(), ImmutableSet.<TypeToken<? extends View>>of());
}
}

View File

@ -0,0 +1,48 @@
/*
* 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;
import com.google.common.reflect.TypeToken;
import org.jclouds.oauth.v2.BaseOauthAuthenticatedRestContextLiveTest;
import org.jclouds.rest.RestContext;
import org.testng.annotations.Test;
/**
* @author David Alves
*/
@Test(groups = "live")
public class GoogleComputeAuthenticatedRestContextLiveTest extends BaseOauthAuthenticatedRestContextLiveTest {
public GoogleComputeAuthenticatedRestContextLiveTest() {
provider = "google-compute";
}
@Override
public String getScopes() {
return GoogleComputeConstants.COMPUTE_SCOPE;
}
@Override
protected TypeToken<RestContext<GoogleComputeApi, GoogleComputeAsyncApi>> contextType() {
return GoogleComputeApiMetadata.CONTEXT_TOKEN;
}
}

View File

@ -0,0 +1,170 @@
/*
* 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.GoogleComputeApi;
import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest;
import org.jclouds.googlecompute.options.ListOptions;
import org.jclouds.googlecompute.parse.ParseOperationListTest;
import org.jclouds.googlecompute.parse.ParseOperationTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
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.assertNull;
import static org.testng.Assert.assertTrue;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class OperationApiExpectTest extends BaseGoogleComputeExpectTest<GoogleComputeApi> {
private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" +
".com/compute/v1beta13/projects/myproject/operations";
public void testGetOperationResponseIs2xx() throws Exception {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/operation.json")).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getOperationApiForProject("myproject");
assertEquals(operationApi.get("operation-1352178598164-4cdcc9d031510-4aa46279"),
new ParseOperationTest().expected());
}
public void testGetOperationResponseIs4xx() throws Exception {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getOperationApiForProject("myproject");
assertNull(operationApi.get("operation-1352178598164-4cdcc9d031510-4aa46279"));
}
public void testDeleteOperationResponseIs2xx() throws Exception {
HttpRequest delete = HttpRequest
.builder()
.method("DELETE")
.endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
TOKEN_RESPONSE, delete, operationResponse).getOperationApiForProject("myproject");
operationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
}
public void testDeleteOperationResponseIs4xx() throws Exception {
HttpRequest delete = HttpRequest
.builder()
.method("DELETE")
.endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
TOKEN_RESPONSE, delete, operationResponse).getOperationApiForProject("myproject");
operationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
}
public void testLisOperationWithNoOptionsResponseIs2xx() {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(OPERATIONS_URL_PREFIX)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/operation_list.json")).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getOperationApiForProject("myproject");
assertEquals(operationApi.listFirstPage().toString(),
new ParseOperationListTest().expected().toString());
}
public void testListOperationWithPaginationOptionsResponseIs2xx() {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(OPERATIONS_URL_PREFIX +
"?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
"VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
"filter=" +
"status%20eq%20done&" +
"maxResults=3")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/operation_list.json")).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getOperationApiForProject("myproject");
assertEquals(operationApi.listAtMarker("CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" +
"I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
new ListOptions.Builder().filter("status eq done").maxResults(3)).toString(),
new ParseOperationListTest().expected().toString());
}
public void testListOperationWithPaginationOptionsResponseIs4xx() {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(OPERATIONS_URL_PREFIX)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
OperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getOperationApiForProject("myproject");
assertTrue(operationApi.list().concat().isEmpty());
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.base.Predicate;
import com.google.common.collect.Iterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.internal.BaseGoogleComputeApiLiveTest;
import org.jclouds.googlecompute.options.ListOptions;
import org.testng.annotations.Test;
import java.util.concurrent.atomic.AtomicInteger;
import static org.jclouds.googlecompute.features.ProjectApiLiveTest.addItemToMetadata;
import static org.jclouds.googlecompute.features.ProjectApiLiveTest.deleteItemFromMetadata;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
/**
* @author David Alves
*/
public class OperationApiLiveTest extends BaseGoogleComputeApiLiveTest {
private static final String METADATA_ITEM_KEY = "operationLiveTestTestProp";
private static final String METADATA_ITEM_VALUE = "operationLiveTestTestValue";
private Operation addOperation;
private Operation deleteOperation;
private OperationApi api() {
return context.getApi().getOperationApiForProject(getUserProject());
}
@Test(groups = "live")
public void testCreateOperations() {
//create some operations by adding and deleting metadata items
// this will make sure there is stuff to listFirstPage
addOperation = assertOperationDoneSucessfully(addItemToMetadata(context.getApi().getProjectApi(),
getUserProject(), METADATA_ITEM_KEY, METADATA_ITEM_VALUE), 20);
deleteOperation = assertOperationDoneSucessfully(deleteItemFromMetadata(context.getApi()
.getProjectApi(), getUserProject(), METADATA_ITEM_KEY), 20);
assertNotNull(addOperation);
assertNotNull(deleteOperation);
}
@Test(groups = "live", dependsOnMethods = "testCreateOperations")
public void testGetOperation() {
Operation operation = api().get(addOperation.getName());
assertNotNull(operation);
assertOperationEquals(operation, this.addOperation);
}
@Test(groups = "live", dependsOnMethods = "testCreateOperations")
public void testListOperationsWithFiltersAndPagination() {
PagedIterable<Operation> operations = api().list(new ListOptions.Builder()
.filter("operationType eq setMetadata")
.maxResults(1));
// make sure that in spite of having only one result per page we get at least two results
final AtomicInteger counter = new AtomicInteger();
operations.firstMatch(new Predicate<IterableWithMarker<Operation>>() {
@Override
public boolean apply(IterableWithMarker<Operation> input) {
counter.addAndGet(Iterables.size(input));
return counter.get() == 2;
}
});
}
private void assertOperationEquals(Operation result, Operation expected) {
assertEquals(result.getName(), expected.getName());
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.GoogleComputeApi;
import org.jclouds.googlecompute.GoogleComputeConstants;
import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest;
import org.jclouds.googlecompute.parse.ParseMetadataTest;
import org.jclouds.googlecompute.parse.ParseOperationTest;
import org.jclouds.googlecompute.parse.ParseProjectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import javax.ws.rs.core.MediaType;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ProjectApiExpectTest extends BaseGoogleComputeExpectTest<GoogleComputeApi> {
public static final String PROJECTS_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects";
public void testGetProjectResponseIs2xx() throws Exception {
HttpRequest getProjectRequest = HttpRequest
.builder()
.method("GET")
.endpoint(PROJECTS_URL_PREFIX + "/myproject")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse getProjectResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/project.json")).build();
ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeConstants.COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, getProjectRequest,
getProjectResponse).getProjectApi();
assertEquals(api.get("myproject"), new ParseProjectTest().expected());
}
public void testGetProjectResponseIs4xx() throws Exception {
HttpRequest getProjectRequest = HttpRequest
.builder()
.method("GET")
.endpoint(PROJECTS_URL_PREFIX + "/myproject")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse getProjectResponse = HttpResponse.builder().statusCode(404).build();
ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeConstants.COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, getProjectRequest,
getProjectResponse).getProjectApi();
assertNull(api.get("myproject"));
}
public void testSetCommonInstanceMetadata() {
HttpRequest setMetadata = HttpRequest
.builder()
.method("POST")
.endpoint(PROJECTS_URL_PREFIX + "/myproject/setCommonInstanceMetadata")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN)
.payload(payloadFromResourceWithContentType("/metadata.json", MediaType.APPLICATION_JSON))
.build();
HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/operation.json")).build();
ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeConstants.COMPUTE_SCOPE),
TOKEN_RESPONSE, setMetadata,
setMetadataResponse).getProjectApi();
assertEquals(api.setCommonInstanceMetadata("myproject", new ParseMetadataTest().expected()),
new ParseOperationTest().expected());
}
}

View File

@ -0,0 +1,123 @@
/*
* 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;
/**
* @author David Alves
*/
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.domain.Project;
import org.jclouds.googlecompute.internal.BaseGoogleComputeApiLiveTest;
import org.testng.annotations.Test;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.not;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
/**
* @author David Alves
*/
public class ProjectApiLiveTest extends BaseGoogleComputeApiLiveTest {
private static final String METADATA_ITEM_KEY = "projectLiveTestTestProp";
private static final String METADATA_ITEM_VALUE = "projectLiveTestTestValue";
private ProjectApi projectApi() {
return context.getApi().getProjectApi();
}
private Project project;
private int initialMetadataSize;
@Test(groups = "live")
public void testGetProjectWhenExists() {
this.project = projectApi().get(getUserProject());
assertNotNull(project);
assertNotNull(project.getId());
assertNotNull(project.getName());
}
@Test(groups = "live")
public void testGetProjectWhenNotExists() {
Project project = projectApi().get("momma");
assertNull(project);
}
@Test(groups = "live", dependsOnMethods = "testGetProjectWhenExists")
public void addItemToMetadata() {
this.initialMetadataSize = project.getCommonInstanceMetadata().size();
assertOperationDoneSucessfully(addItemToMetadata(projectApi(), getUserProject(), METADATA_ITEM_KEY,
METADATA_ITEM_VALUE), 20);
this.project = projectApi().get(getUserProject());
assertNotNull(project);
assertTrue(this.project.getCommonInstanceMetadata().containsKey(METADATA_ITEM_KEY),
this.project.toString());
assertEquals(this.project.getCommonInstanceMetadata().get(METADATA_ITEM_KEY),
METADATA_ITEM_VALUE);
}
@Test(groups = "live", dependsOnMethods = "addItemToMetadata")
public void testDeleteItemFromMetadata() {
assertOperationDoneSucessfully(deleteItemFromMetadata(projectApi(), getUserProject(), METADATA_ITEM_KEY), 20);
this.project = projectApi().get(getUserProject());
assertNotNull(project);
assertFalse(project.getCommonInstanceMetadata().containsKey(METADATA_ITEM_KEY));
assertSame(this.project.getCommonInstanceMetadata().size(), initialMetadataSize);
}
/**
* Adds an item to the Project's metadata
* <p/>
* Beyond it's use here it is also used as a cheap way of generating Operations to both test the OperationApi and
* the pagination system.
*/
public static Operation addItemToMetadata(ProjectApi projectApi, String projectName, String key, String value) {
Project project = projectApi.get(projectName);
assertNotNull(project);
ImmutableMap.Builder<String, String> metadataBuilder = ImmutableMap.builder();
metadataBuilder.putAll(project.getCommonInstanceMetadata());
metadataBuilder.put(key, value);
return projectApi.setCommonInstanceMetadata(projectName, metadataBuilder.build());
}
/**
* Deletes an item from the Project's metadata
* <p/>
* Beyond it's use here it is also used as a cheap way of generating Operation's to both test the OperationApi and
* the pagination system.
*/
public static Operation deleteItemFromMetadata(ProjectApi projectApi, String projectName, String key) {
Project project = projectApi.get(projectName);
assertNotNull(project);
ImmutableMap.Builder<String, String> metadataBuilder = ImmutableMap.builder();
metadataBuilder.putAll(Maps.filterKeys(project.getCommonInstanceMetadata(), not(equalTo(key))));
return projectApi.setCommonInstanceMetadata(projectName, metadataBuilder.build());
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.GoogleComputeApi;
import org.jclouds.googlecompute.internal.BaseGoogleComputeExpectTest;
import org.jclouds.googlecompute.parse.ParseZoneListTest;
import org.jclouds.googlecompute.parse.ParseZoneTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_READONLY_SCOPE;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ZoneApiExpectTest extends BaseGoogleComputeExpectTest<GoogleComputeApi> {
public static final String ZONES_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects/google/zones";
public void testGetZoneResponseIs2xx() throws Exception {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(ZONES_URL_PREFIX + "/us-central2-a")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/zone_get.json")).build();
ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getZoneApiForProject("google");
assertEquals(api.get("us-central2-a"),
new ParseZoneTest().expected());
}
public void testGetZoneResponseIs4xx() throws Exception {
HttpRequest get = HttpRequest
.builder()
.method("GET")
.endpoint(ZONES_URL_PREFIX + "/us-central2-a")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, get, operationResponse).getZoneApiForProject("google");
assertNull(api.get("us-central2-a"));
}
public void testListZoneNoOptionsResponseIs2xx() throws Exception {
HttpRequest list = HttpRequest
.builder()
.method("GET")
.endpoint(ZONES_URL_PREFIX)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/zone_list.json")).build();
ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, list, operationResponse).getZoneApiForProject("google");
assertEquals(api.listFirstPage().toString(),
new ParseZoneListTest().expected().toString());
}
public void testListZoneWithPaginationOptionsResponseIs4xx() {
HttpRequest list = HttpRequest
.builder()
.method("GET")
.endpoint(ZONES_URL_PREFIX)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + TOKEN).build();
HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
TOKEN_RESPONSE, list, operationResponse).getZoneApiForProject("google");
assertTrue(api.list().concat().isEmpty());
}
}

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.features;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.googlecompute.domain.Zone;
import org.jclouds.googlecompute.internal.BaseGoogleComputeApiLiveTest;
import org.jclouds.googlecompute.options.ListOptions;
import org.testng.annotations.Test;
import java.util.Iterator;
import java.util.List;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
/**
* @author David Alves
*/
public class ZoneApiLiveTest extends BaseGoogleComputeApiLiveTest {
private Zone zone;
private ZoneApi api() {
return context.getApi().getZoneApiForProject(getUserProject());
}
@Test(groups = "live")
public void testListZone() {
PagedIterable<Zone> zones = api().list(new ListOptions.Builder()
.maxResults(1));
Iterator<IterableWithMarker<Zone>> pageIterator = zones.iterator();
assertTrue(pageIterator.hasNext());
IterableWithMarker<Zone> singlePageIterator = pageIterator.next();
List<Zone> zoneAsList = Lists.newArrayList(singlePageIterator);
assertSame(zoneAsList.size(), 1);
this.zone = Iterables.getOnlyElement(zoneAsList);
}
@Test(groups = "live", dependsOnMethods = "testListZone")
public void testGetZone() {
Zone zone = api().get(this.zone.getName());
assertNotNull(zone);
assertZoneEquals(zone, this.zone);
}
private void assertZoneEquals(Zone result, Zone expected) {
assertEquals(result.getName(), expected.getName());
}
}

View File

@ -0,0 +1,97 @@
/**
* 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 org.easymock.IArgumentMatcher;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import java.net.URI;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.EasyMock.verify;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "GoogleComputeErrorHandlerTest")
public class GoogleComputeErrorHandlerTest {
@Test
public void test409MakesIllegalStateException() {
assertCodeMakes(
"POST",
URI.create("https://www.googleapis.com/compute/v1beta13"),
409,
"HTTP/1.1 409 Conflict",
"\"{\"code\":\"InvalidState\",\"message\":\"An incompatible transition has already been queued for this" +
" resource\"}\"",
IllegalStateException.class);
}
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
Class<? extends Exception> expected) {
assertCodeMakes(method, uri, statusCode, message, "application/json", content, expected);
}
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
String content, Class<? extends Exception> expected) {
GoogleComputeErrorHandler function = new GoogleComputeErrorHandler();
HttpCommand command = createMock(HttpCommand.class);
HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build();
HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
response.getPayload().getContentMetadata().setContentType(contentType);
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
command.setException(classEq(expected));
replay(command);
function.handleError(command, response);
verify(command);
}
public static Exception classEq(final Class<? extends Exception> in) {
reportMatcher(new IArgumentMatcher() {
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("classEq(");
buffer.append(in);
buffer.append(")");
}
@Override
public boolean matches(Object arg) {
return arg.getClass() == in;
}
});
return null;
}
}

View File

@ -0,0 +1,28 @@
/**
* 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.internal;
import org.jclouds.googlecompute.GoogleComputeApi;
/**
* @author Adrian Cole
*/
public class BaseGoogleComputeApiExpectTest extends BaseGoogleComputeExpectTest<GoogleComputeApi> {
}

View File

@ -0,0 +1,132 @@
/**
* 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.internal;
import com.google.common.base.Predicate;
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;
import org.jclouds.googlecompute.GoogleComputeAsyncApi;
import org.jclouds.googlecompute.config.UserProject;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.oauth.v2.OAuthTestUtils;
import org.jclouds.predicates.Retryables;
import org.jclouds.rest.RestContext;
import java.net.URI;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
/**
* @author David Alves
*/
public class BaseGoogleComputeApiLiveTest extends BaseContextLiveTest<RestContext<GoogleComputeApi,
GoogleComputeAsyncApi>> {
protected static final String API_URL_PREFIX = "https://www.googleapis.com/compute/v1beta13/projects/";
protected static final String ZONE_API_URL_SUFFIX = "/zones/";
protected static final String DEFAULT_ZONE_NAME = "us-east1-a";
protected static final String NETWORK_API_URL_SUFFIX = "/networks/";
protected static final String DEFAULT_NETWORK_NAME = "default";
protected static final String MACHINE_TYPE_API_URL_SUFFIX = "/machineTypes/";
protected static final String DEFAULT_MACHINE_TYPE_NAME = "n1-standard-1";
protected static final String GOOGLE_PROJECT = "google";
public BaseGoogleComputeApiLiveTest() {
provider = "google-compute";
}
@Override
protected Properties setupProperties() {
Properties properties = super.setupProperties();
OAuthTestUtils.setCredentialFromPemFile(properties, "google-compute.credential");
return properties;
}
@Override
protected TypeToken<RestContext<GoogleComputeApi, GoogleComputeAsyncApi>> contextType() {
return GoogleComputeApiMetadata.CONTEXT_TOKEN;
}
protected String getUserProject() {
return context.utils().injector().getInstance(Key.get(String.class, UserProject.class));
}
protected Predicate<AtomicReference<Operation>> getOperationDonePredicate() {
return context.utils().getInjector().getInstance(Key.get(new TypeLiteral<Predicate<AtomicReference<Operation>>>
() {}));
}
protected Operation assertOperationDoneSucessfully(Operation operation, long maxWaitSeconds) {
operation = waitOperationDone(operation, maxWaitSeconds);
assertEquals(operation.getStatus(), Operation.Status.DONE);
assertTrue(operation.getErrors().isEmpty());
return operation;
}
protected Operation waitOperationDone(Operation operation, long maxWaitSeconds) {
return waitOperationDone(getOperationDonePredicate(), operation, maxWaitSeconds);
}
protected URI getDefaultZoneUrl(String project) {
return getZoneUrl(project, DEFAULT_ZONE_NAME);
}
protected URI getZoneUrl(String project, String zone) {
return URI.create(API_URL_PREFIX + project + ZONE_API_URL_SUFFIX + zone);
}
protected URI getDefaultNetworkUrl(String project) {
return getNetworkUrl(project, DEFAULT_NETWORK_NAME);
}
protected URI getNetworkUrl(String project, String network) {
return URI.create(API_URL_PREFIX + project + NETWORK_API_URL_SUFFIX + network);
}
protected URI getDefaultMachineTypekUrl(String project) {
return gettMachineTypeUrl(project, DEFAULT_MACHINE_TYPE_NAME);
}
protected URI gettMachineTypeUrl(String project, String machineType) {
return URI.create(API_URL_PREFIX + project + MACHINE_TYPE_API_URL_SUFFIX + machineType);
}
protected static Operation waitOperationDone(Predicate<AtomicReference<Operation>> operationDonePredicate,
Operation operation, long maxWaitSeconds) {
AtomicReference<Operation> operationReference = new AtomicReference<Operation>(operation);
Retryables.retry(operationDonePredicate, operationReference, maxWaitSeconds, 1, TimeUnit.SECONDS);
return operationReference.get();
}
}

View File

@ -0,0 +1,36 @@
/**
* 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.internal;
import com.google.common.base.Function;
import com.google.inject.Module;
import org.jclouds.googlecompute.GoogleComputeAsyncApi;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import java.util.Properties;
/**
* @author Adrian Cole
*/
public class BaseGoogleComputeAsyncApiExpectTest extends BaseGoogleComputeExpectTest<GoogleComputeAsyncApi> {
public GoogleComputeAsyncApi createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
return createInjector(fn, module, props).getInstance(GoogleComputeAsyncApi.class);
}
}

View File

@ -0,0 +1,117 @@
/**
* 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.internal;
import com.google.common.base.Joiner;
import com.google.common.base.Ticker;
import com.google.inject.Binder;
import com.google.inject.Module;
import org.jclouds.collect.PagedIterable;
import org.jclouds.collect.PagedIterables;
import org.jclouds.googlecompute.domain.ListPage;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.oauth.v2.OAuthConstants;
import org.jclouds.rest.internal.BaseRestApiExpectTest;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Properties;
import static org.jclouds.crypto.CryptoStreams.base64Url;
/**
* @author Adrian Cole
*/
public class BaseGoogleComputeExpectTest<T> extends BaseRestApiExpectTest<T> {
private static final String header = "{\"alg\":\"none\",\"typ\":\"JWT\"}";
private static final String CLAIMS_TEMPLATE = "{" +
"\"iss\":\"identity\"," +
"\"scope\":\"%s\"," +
"\"aud\":\"https://accounts.google.com/o/oauth2/token\"," +
"\"exp\":3600," +
"\"iat\":0}";
protected static final String TOKEN = "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M";
protected static final HttpResponse TOKEN_RESPONSE = HttpResponse.builder().statusCode(200).payload(
payloadFromString("{\n" +
" \"access_token\" : \"" + TOKEN + "\",\n" +
" \"token_type\" : \"Bearer\",\n" +
" \"expires_in\" : 3600\n" +
"}")).build();
public BaseGoogleComputeExpectTest() {
provider = "google-compute";
}
@Override
protected Module createModule() {
return new Module() {
@Override
public void configure(Binder binder) {
binder.bind(Ticker.class).toInstance(new Ticker() {
@Override
public long read() {
return 0;
}
});
}
};
}
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
// use no sig algorithm for expect tests (means no credential is required either)
props.put("jclouds.oauth.signature-or-mac-algorithm", OAuthConstants.NO_ALGORITHM);
return props;
}
protected HttpRequest requestForScopes(String... scopes) {
String claims = String.format(CLAIMS_TEMPLATE, Joiner.on(",").join(scopes));
String payload = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" +
// Base64 Encoded Header
"assertion=" + base64Url(header.getBytes(Charset.forName("UTF-8"))) + "." +
// Base64 Encoded Claims
base64Url(claims.getBytes(Charset.forName("UTF-8"))) + ".";
return HttpRequest.builder()
.method("POST")
.endpoint(URI.create("https://accounts.google.com/o/oauth2/token"))
.addHeader("Accept", MediaType.APPLICATION_JSON)
.payload(payloadFromStringWithContentType(payload, "application/x-www-form-urlencoded"))
.build();
}
/**
* Parse tests don't apply @Transform so we need to apply the transformation to PagedIterable on the result of
* expected()
*/
protected <T> PagedIterable<T> toPagedIterable(ListPage<T> list) {
return PagedIterables.of(list);
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.internal;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.jclouds.googlecompute.config.GoogleComputeParserModule;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
/**
* @author David Alves
*/
public abstract class BaseGoogleComputeParseTest<T> extends BaseItemParserTest<T> {
@Override
protected Injector injector() {
return Guice.createInjector(new GsonModule(), new GoogleComputeParserModule());
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.googlecompute.config.GoogleComputeParserModule;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseMetadataTest extends BaseGoogleComputeParseTest<GoogleComputeParserModule.Metadata> {
@Override
public String resource() {
return "/metadata.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public GoogleComputeParserModule.Metadata expected() {
return new GoogleComputeParserModule.Metadata(
ImmutableMap.<String, String>builder()
.put("propA", "valueA")
.put("propB", "valueB")
.build());
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.ListPage;
import org.jclouds.googlecompute.domain.Operation;
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 ParseOperationListTest extends BaseGoogleComputeParseTest<ListPage<Operation>> {
@Override
public String resource() {
return "/operation_list.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public ListPage<Operation> expected() {
return ListPage.<Operation>builder()
.kind(Resource.Kind.OPERATION_LIST)
.id("projects/myproject/operations")
.selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/operations"))
.addItem(new ParseOperationTest().expected())
.build();
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.date.internal.SimpleDateFormatDateService;
import org.jclouds.googlecompute.domain.Operation;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.net.URI;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseOperationTest extends BaseGoogleComputeParseTest<Operation> {
@Override
public String resource() {
return "/operation.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Operation expected() {
SimpleDateFormatDateService dateService = new SimpleDateFormatDateService();
return Operation.builder().id("13053095055850848306")
.selfLink(URI.create("https://www.googleapis" +
".com/compute/v1beta13/projects/myproject/operations/operation" +
"-1354084865060-4cf88735faeb8-bbbb12cb"))
.name("operation-1354084865060-4cf88735faeb8-bbbb12cb")
.targetLink(URI.create("https://www.googleapis" +
".com/compute/v1beta13/projects/myproject/instances/instance-api-live" +
"-test-instance"))
.targetId("13053094017547040099")
.status(Operation.Status.DONE)
.user("user@developer.gserviceaccount.com")
.progress(100)
.insertTime(dateService.iso8601DateParse("2012-11-28T06:41:05.060"))
.startTime(dateService.iso8601DateParse("2012-11-28T06:41:05.142"))
.operationType("insert")
.httpErrorStatusCode(400)
.httpErrorMessage("BAD REQUEST")
.addError(Operation.Error.builder()
.code("RESOURCE_ALREADY_EXISTS")
.message("The resource " +
"'projects/myproject/instances/instance-api-live-test-instance' already" +
" exists")
.build())
.build();
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.googlecompute.domain.Project;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import java.util.Date;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseProjectTest extends BaseGoogleComputeParseTest<Project> {
@Override
public String resource() {
return "/project.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Project expected() {
return Project.builder()
.id("13024414184846275913")
.creationTimestamp(new Date(Long.parseLong("1351109596252")))
.selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject"))
.name("myproject")
.description("")
.commonInstanceMetadata(
ImmutableMap.<String, String>builder()
.put("propA", "valueA")
.put("propB", "valueB")
.build())
.addQuota("INSTANCES", 0, 8)
.addQuota("CPUS", 0, 8)
.addQuota("EPHEMERAL_ADDRESSES", 0, 8)
.addQuota("DISKS", 0, 8)
.addQuota("DISKS_TOTAL_GB", 0, 100)
.addQuota("SNAPSHOTS", 0, 1000)
.addQuota("NETWORKS", 1, 5)
.addQuota("FIREWALLS", 2, 100)
.addQuota("IMAGES", 0, 100)
.build();
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.Project;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseQuotaTest extends BaseGoogleComputeParseTest<Project.Quota> {
@Override
public String resource() {
return "/quota.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Project.Quota expected() {
return Project.Quota.builder().metric("INSTANCES").usage(0.0).limit(8.0).build();
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.date.internal.SimpleDateFormatDateService;
import org.jclouds.googlecompute.domain.ListPage;
import org.jclouds.googlecompute.domain.Resource;
import org.jclouds.googlecompute.domain.Zone;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.net.URI;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseZoneListTest extends BaseGoogleComputeParseTest<ListPage<Zone>> {
@Override
public String resource() {
return "/zone_list.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public ListPage<Zone> expected() {
return ListPage.<Zone>builder()
.kind(Resource.Kind.ZONE_LIST)
.id("projects/google/zones")
.selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/google/zones"))
.items(ImmutableSet.of(
new ParseZoneTest().expected()
, Zone.builder()
.id("13024414164050619686")
.creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse
("2012-10-24T20:13:19.271"))
.selfLink(URI.create("https://www.googleapis" +
".com/compute/v1beta13/projects/google/zones/us-east1-a"))
.name("us-east1-a")
.description("us-east1-a")
.status(Zone.Status.UP)
.addMaintenanceWindow(Zone.MaintenanceWindow.builder()
.name("2013-02-17-planned-outage")
.description("maintenance zone")
.beginTime(new SimpleDateFormatDateService().iso8601DateParse
("2013-02-17T08:00:00.000"))
.endTime(new SimpleDateFormatDateService().iso8601DateParse
("2013-03-03T08:00:00.000"))
.build())
.build()))
.build();
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.date.internal.SimpleDateFormatDateService;
import org.jclouds.googlecompute.domain.Zone;
import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.net.URI;
/**
* @author David Alves
*/
@Test(groups = "unit")
public class ParseZoneTest extends BaseGoogleComputeParseTest<Zone> {
@Override
public String resource() {
return "/zone_get.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Zone expected() {
return Zone.builder()
.id("13020128040171887099")
.creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-10-19T16:42:54.131"))
.selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/google/zones/us-central2-a"))
.name("us-central2-a")
.description("us-central2-a")
.status(Zone.Status.DOWN)
.addMaintenanceWindow(Zone.MaintenanceWindow.builder()
.name("2012-11-10-planned-outage")
.description("maintenance zone")
.beginTime(new SimpleDateFormatDateService().iso8601DateParse("2012-11-10T20:00:00.000"))
.endTime(new SimpleDateFormatDateService().iso8601DateParse("2012-12-02T20:00:00.000"))
.build())
.build();
}
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<configuration scan="false">
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>
</appender>
<appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-wire.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>
</appender>
<root>
<level value="warn"/>
</root>
<logger name="org.jclouds">
<level value="DEBUG"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="jclouds.wire">
<level value="DEBUG"/>
<appender-ref ref="WIREFILE"/>
</logger>
<logger name="jclouds.headers">
<level value="DEBUG"/>
<appender-ref ref="WIREFILE"/>
</logger>
</configuration>

View File

@ -0,0 +1 @@
{"kind":"compute#metadata","items":[{"key":"propA","value":"valueA"},{"key":"propB","value":"valueB"}]}

View File

@ -0,0 +1,24 @@
{
"kind": "compute#operation",
"id": "13053095055850848306",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
"name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
"targetLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/instances/instance-api-live-test-instance",
"targetId": "13053094017547040099",
"status": "DONE",
"user": "user@developer.gserviceaccount.com",
"progress": 100,
"insertTime": "2012-11-28T06:41:05.060",
"startTime": "2012-11-28T06:41:05.142",
"httpErrorStatusCode": 400,
"httpErrorMessage": "BAD REQUEST",
"error": {
"errors": [
{
"code": "RESOURCE_ALREADY_EXISTS",
"message": "The resource 'projects/myproject/instances/instance-api-live-test-instance' already exists"
}
]
},
"operationType": "insert"
}

View File

@ -0,0 +1,31 @@
{
"kind": "compute#operationList",
"id": "projects/myproject/operations",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/operations",
"items": [
{
"kind": "compute#operation",
"id": "13053095055850848306",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
"name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
"targetLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject/instances/instance-api-live-test-instance",
"targetId": "13053094017547040099",
"status": "DONE",
"user": "user@developer.gserviceaccount.com",
"progress": 100,
"insertTime": "2012-11-28T06:41:05.060",
"startTime": "2012-11-28T06:41:05.142",
"httpErrorStatusCode": 400,
"httpErrorMessage": "BAD REQUEST",
"error": {
"errors": [
{
"code": "RESOURCE_ALREADY_EXISTS",
"message": "The resource 'projects/myproject/instances/instance-api-live-test-instance' already exists"
}
]
},
"operationType": "insert"
}
]
}

View File

@ -0,0 +1,68 @@
{
"kind": "compute#project",
"id": "13024414184846275913",
"creationTimestamp": "2012-10-24T20:13:16.252",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/myproject",
"name": "myproject",
"description": "",
"commonInstanceMetadata": {
"kind": "compute#metadata",
"items": [
{
"key": "propA",
"value": "valueA"
},
{
"key": "propB",
"value": "valueB"
}
]
},
"quotas": [
{
"metric": "INSTANCES",
"usage": 0,
"limit": 8
},
{
"metric": "CPUS",
"usage": 0,
"limit": 8
},
{
"metric": "EPHEMERAL_ADDRESSES",
"usage": 0,
"limit": 8
},
{
"metric": "DISKS",
"usage": 0,
"limit": 8
},
{
"metric": "DISKS_TOTAL_GB",
"usage": 0,
"limit": 100
},
{
"metric": "SNAPSHOTS",
"usage": 0,
"limit": 1000
},
{
"metric": "NETWORKS",
"usage": 1,
"limit": 5
},
{
"metric": "FIREWALLS",
"usage": 2,
"limit": 100
},
{
"metric": "IMAGES",
"usage": 0,
"limit": 100
}
]
}

View File

@ -0,0 +1,5 @@
{
"metric": "INSTANCES",
"usage": 0,
"limit": 8
}

View File

@ -0,0 +1,17 @@
{
"kind": "compute#zone",
"id": "13020128040171887099",
"creationTimestamp": "2012-10-19T16:42:54.131",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/zones/us-central2-a",
"name": "us-central2-a",
"description": "us-central2-a",
"status": "DOWN",
"maintenanceWindows": [
{
"name": "2012-11-10-planned-outage",
"description": "maintenance zone",
"beginTime": "2012-11-10T20:00:00.000",
"endTime": "2012-12-02T20:00:00.000"
}
]
}

View File

@ -0,0 +1,41 @@
{
"kind": "compute#zoneList",
"id": "projects/google/zones",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/zones",
"items": [
{
"kind": "compute#zone",
"id": "13020128040171887099",
"creationTimestamp": "2012-10-19T16:42:54.131",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/zones/us-central2-a",
"name": "us-central2-a",
"description": "us-central2-a",
"status": "DOWN",
"maintenanceWindows": [
{
"name": "2012-11-10-planned-outage",
"description": "maintenance zone",
"beginTime": "2012-11-10T20:00:00.000",
"endTime": "2012-12-02T20:00:00.000"
}
]
},
{
"kind": "compute#zone",
"id": "13024414164050619686",
"creationTimestamp": "2012-10-24T20:13:19.271",
"selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/zones/us-east1-a",
"name": "us-east1-a",
"description": "us-east1-a",
"status": "UP",
"maintenanceWindows": [
{
"name": "2013-02-17-planned-outage",
"description": "maintenance zone",
"beginTime": "2013-02-17T08:00:00.000",
"endTime": "2013-03-03T08:00:00.000"
}
]
}
]
}

View File

@ -45,6 +45,7 @@
<module>cdmi</module> <module>cdmi</module>
<module>joyent-cloudapi</module> <module>joyent-cloudapi</module>
<module>joyentcloud</module> <module>joyentcloud</module>
<module>google-compute</module>
<module>greenqloud-compute</module> <module>greenqloud-compute</module>
<module>greenqloud-storage</module> <module>greenqloud-storage</module>
<module>iam</module> <module>iam</module>