From 8e8f9662e17ee673c5e3417c30a0c9e507a42682 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 5 Nov 2014 23:02:53 -0800 Subject: [PATCH] Add GoogleComputeEngineProviderMetadata and implement dynamic Location suppliers. --- .../GoogleComputeEngineApiMetadata.java | 38 ++- .../GoogleComputeEngineConstants.java | 20 -- .../GoogleComputeEngineProviderMetadata.java | 72 +++++ .../GoogleComputeEngineServiceAdapter.java | 37 ++- ...ogleComputeEngineServiceContextModule.java | 254 ++++++------------ .../functions/BuildInstanceMetadata.java | 9 +- .../functions/CreateNetworkIfNeeded.java | 6 - .../InstanceInZoneToNodeMetadata.java | 26 +- .../MachineTypeInZoneToHardware.java | 41 ++- .../OrphanedGroupsFromDeadNodes.java | 12 +- .../compute/functions/RegionToLocation.java | 45 ---- .../compute/functions/ZoneToLocation.java | 45 ---- .../GoogleComputeEngineTemplateOptions.java | 2 +- .../GoogleComputeEngineHttpApiModule.java | 76 ++---- .../GoogleComputeEngineLocationModule.java | 194 +++++++++++++ .../GoogleComputeEngineParserModule.java | 40 +-- .../RegionOperationDonePredicate.java | 9 +- .../ZoneOperationDonePredicate.java | 9 +- ...gleComputeEngineProviderMetadataTest.java} | 22 +- .../GoogleComputeEngineServiceExpectTest.java | 244 ++++++++--------- .../InstanceInZoneToNodeMetadataTest.java | 12 +- .../OrphanedGroupsFromDeadNodesTest.java | 18 +- .../features/InstanceApiLiveTest.java | 1 - .../features/RegionApiExpectTest.java | 5 +- .../BaseGoogleComputeEngineExpectTest.java | 66 ++--- .../parse/ParseRegionListTest.java | 2 +- .../parse/ParseRegionTest.java | 4 +- .../src/test/resources/region_get.json | 4 +- .../src/test/resources/region_list.json | 6 +- 29 files changed, 654 insertions(+), 665 deletions(-) create mode 100644 providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadata.java delete mode 100644 providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/RegionToLocation.java delete mode 100644 providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java create mode 100644 providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineLocationModule.java rename providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/{GoogleComputeEngineApiMetadataTest.java => GoogleComputeEngineProviderMetadataTest.java} (55%) diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java index 6584d18c02..0c9a23ccb8 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java @@ -19,7 +19,6 @@ package org.jclouds.googlecomputeengine; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS; -import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_PROVIDER_NAME; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; @@ -29,7 +28,6 @@ import static org.jclouds.reflect.Reflection2.typeToken; import java.net.URI; import java.util.Properties; -import org.jclouds.apis.ApiMetadata; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.googlecomputeengine.compute.config.GoogleComputeEngineServiceContextModule; import org.jclouds.googlecomputeengine.config.GoogleComputeEngineHttpApiModule; @@ -38,11 +36,9 @@ import org.jclouds.oauth.v2.config.OAuthAuthenticationModule; import org.jclouds.oauth.v2.config.OAuthModule; import org.jclouds.rest.internal.BaseHttpApiMetadata; -import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -@AutoService(ApiMetadata.class) public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata { @Override @@ -64,9 +60,9 @@ public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata { protected Builder() { - id(GCE_PROVIDER_NAME) - .name("Google Compute Engine Api") - .identityName("Email associated with the Google API client_id") - .credentialName("Private key literal associated with the Google API client_id") - .documentation(URI.create("https://developers.google.com/compute/docs")) - .version("v1") - .defaultEndpoint("https://www.googleapis.com/compute/v1") - .defaultProperties(GoogleComputeEngineApiMetadata.defaultProperties()) - .view(typeToken(ComputeServiceContext.class)) - .defaultModules(ImmutableSet.>builder() - .add(GoogleComputeEngineHttpApiModule.class) - .add(GoogleComputeEngineParserModule.class) - .add(OAuthAuthenticationModule.class) - .add(OAuthModule.class) - .add(GoogleComputeEngineServiceContextModule.class) - .build()); + id("google-compute-engine") + .name("Google Compute Engine Api") + .identityName("Email associated with the Google API client_id") + .credentialName("Private key literal associated with the Google API client_id") + .documentation(URI.create("https://developers.google.com/compute/docs")) + .version("v1") + .defaultEndpoint("https://www.googleapis.com/compute/v1") + .defaultProperties(GoogleComputeEngineApiMetadata.defaultProperties()) + .view(typeToken(ComputeServiceContext.class)) + .defaultModules(ImmutableSet.>builder() + .add(GoogleComputeEngineHttpApiModule.class) + .add(GoogleComputeEngineParserModule.class) + .add(OAuthAuthenticationModule.class) + .add(OAuthModule.class) + .add(GoogleComputeEngineServiceContextModule.class) + .build()); } @Override diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java index 16c68a8694..1ab700f5f5 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java @@ -16,30 +16,14 @@ */ package org.jclouds.googlecomputeengine; -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; - import com.google.common.annotations.Beta; public final class GoogleComputeEngineConstants { - public static final String GCE_PROVIDER_NAME = "google-compute-engine"; - - /** - * The name of the project that keeps public resources. - */ - public static final String GOOGLE_PROJECT = "google"; - 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"; - public static final String STORAGE_READONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.read_only"; - - public static final String STORAGE_WRITEONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.write_only"; - - /** * The total time, in msecs, to wait for an operation to complete. */ @@ -52,16 +36,12 @@ public final class GoogleComputeEngineConstants { @Beta public static final String OPERATION_COMPLETE_INTERVAL = "jclouds.google-compute-engine.operation-complete-interval"; - public static final Location GOOGLE_PROVIDER_LOCATION = new LocationBuilder().scope(LocationScope.PROVIDER).id - (GCE_PROVIDER_NAME).description(GCE_PROVIDER_NAME).build(); - /** * The list of projects that will be scanned looking for images. */ @Beta public static final String GCE_IMAGE_PROJECTS = "jclouds.google-compute-engine.image-projects"; - /** * The key we look for in instance metadata for the URI for the image the instance was created from. */ diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadata.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadata.java new file mode 100644 index 0000000000..43c885507d --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadata.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.googlecomputeengine; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.providers.internal.BaseProviderMetadata; + +import com.google.auto.service.AutoService; + +/** Note: This does not set iso3166Codes as Google intentionally does not document them. */ +@AutoService(ProviderMetadata.class) +public final class GoogleComputeEngineProviderMetadata extends BaseProviderMetadata { + + public static Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return builder().fromProviderMetadata(this); + } + + public GoogleComputeEngineProviderMetadata() { + super(builder()); + } + + public GoogleComputeEngineProviderMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + return new Properties(); // currently all are set in the api metadata class. + } + + public static final class Builder extends BaseProviderMetadata.Builder { + + private Builder() { + id("google-compute-engine") // + .name("Google Compute Engine") // + .apiMetadata(new GoogleComputeEngineApiMetadata()) // + .homepage(URI.create("https://cloud.google.com/compute")) // + .console(URI.create("https://console.developers.google.com/project")) // + .defaultProperties(GoogleComputeEngineProviderMetadata.defaultProperties()); + } + + @Override public GoogleComputeEngineProviderMetadata build() { + return new GoogleComputeEngineProviderMetadata(this); + } + + @Override public Builder fromProviderMetadata(ProviderMetadata in) { + super.fromProviderMetadata(in); + return this; + } + } +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java index 0a2bc7d37c..4299eab335 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java @@ -38,7 +38,6 @@ import static org.jclouds.util.Predicates2.retry; import java.net.URI; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -47,7 +46,6 @@ import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.inject.Named; -import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Template; @@ -69,15 +67,16 @@ import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk.Mode; import org.jclouds.googlecomputeengine.domain.ListPage; import org.jclouds.googlecomputeengine.domain.MachineType; import org.jclouds.googlecomputeengine.domain.Operation; -import org.jclouds.googlecomputeengine.domain.Zone; import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate; import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate.PersistentDisk; import org.jclouds.googlecomputeengine.features.DiskApi; import org.jclouds.googlecomputeengine.features.InstanceApi; import org.jclouds.googlecomputeengine.options.DiskCreationOptions; +import org.jclouds.location.Zone; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Splitter; import com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; @@ -88,11 +87,12 @@ import com.google.common.primitives.Ints; import com.google.common.util.concurrent.Atomics; import com.google.common.util.concurrent.UncheckedTimeoutException; -public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAdapter { +public final class GoogleComputeEngineServiceAdapter + implements ComputeServiceAdapter { private final GoogleComputeEngineApi api; private final Supplier userProject; - private final Supplier> zones; + private final Supplier> zoneIds; private final Function> metatadaFromTemplateOptions; private final Predicate> retryOperationDonePredicate; private final long operationCompleteCheckInterval; @@ -107,9 +107,9 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd @Named("zone") Predicate> operationDonePredicate, @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout, - @Memoized Supplier> zones, + @Zone Supplier> zoneIds, FirewallTagNamingConvention.Factory firewallTagNamingConvention, - @Named(GCE_IMAGE_PROJECTS) List imageProjects) { + @Named(GCE_IMAGE_PROJECTS) String imageProjects) { this.api = api; this.userProject = userProject; this.metatadaFromTemplateOptions = metatadaFromTemplateOptions; @@ -117,9 +117,9 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd this.operationCompleteCheckTimeout = operationCompleteCheckTimeout; this.retryOperationDonePredicate = retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, TimeUnit.MILLISECONDS); - this.zones = zones; + this.zoneIds = zoneIds; this.firewallTagNamingConvention = firewallTagNamingConvention; - this.imageProjects = imageProjects; + this.imageProjects = Splitter.on(',').splitToList(imageProjects); } @Override @@ -241,8 +241,8 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd public Iterable listHardwareProfiles() { ImmutableList.Builder builder = ImmutableList.builder(); - for (final Location zone : zones.get().values()) { - for (Iterator> i = api.getMachineTypeApi(userProject.get(), zone.getId()).list(); + for (final String zoneId : zoneIds.get()) { + for (Iterator> i = api.getMachineTypeApi(userProject.get(), zoneId).list(); i.hasNext(); ) { builder.addAll(FluentIterable.from(i.next()).filter(new Predicate() { @Override public boolean apply(MachineType input) { @@ -254,7 +254,6 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd } })); } - } return builder.build(); @@ -288,8 +287,8 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd } @Override - public Iterable listLocations() { - return concat(api.getZoneApi(userProject.get()).list()); + public Iterable listLocations() { + throw new UnsupportedOperationException("Locations are configured in GoogleComputeEngineLocationModule"); } @Override @@ -301,13 +300,13 @@ public final class GoogleComputeEngineServiceAdapter implements ComputeServiceAd @Override public Iterable listNodes() { - return FluentIterable.from(zones.get().values()) - .transformAndConcat(new Function>() { - @Override public Iterable apply(final Location input) { - return transform(concat(api.getInstanceApi(userProject.get(), input.getId()).list()), + return FluentIterable.from(zoneIds.get()) + .transformAndConcat(new Function>() { + @Override public Iterable apply(final String zoneId) { + return transform(concat(api.getInstanceApi(userProject.get(), zoneId).list()), new Function() { @Override public InstanceInZone apply(Instance arg0) { - return InstanceInZone.create(arg0, input.getId()); + return InstanceInZone.create(arg0, zoneId); } }); } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java index c75d3e22c5..76dabd7987 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java @@ -16,18 +16,13 @@ */ package org.jclouds.googlecomputeengine.compute.config; -import static com.google.common.collect.Iterables.transform; -import static com.google.common.collect.Maps.uniqueIndex; +import static com.google.common.base.Suppliers.memoizeWithExpiration; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; -import static org.jclouds.googlecomputeengine.internal.ListPages.concat; -import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS; import java.net.URI; -import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; import javax.inject.Named; import javax.inject.Singleton; @@ -44,7 +39,6 @@ import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; import org.jclouds.domain.Location; -import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineService; import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineServiceAdapter; import org.jclouds.googlecomputeengine.compute.domain.InstanceInZone; @@ -61,29 +55,21 @@ import org.jclouds.googlecomputeengine.compute.functions.InstanceInZoneToNodeMet import org.jclouds.googlecomputeengine.compute.functions.MachineTypeInZoneToHardware; import org.jclouds.googlecomputeengine.compute.functions.NetworkToSecurityGroup; import org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadNodes; -import org.jclouds.googlecomputeengine.compute.functions.RegionToLocation; -import org.jclouds.googlecomputeengine.compute.functions.ZoneToLocation; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.googlecomputeengine.compute.predicates.AllNodesInGroupTerminated; import org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.googlecomputeengine.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.googlecomputeengine.compute.strategy.UseNodeCredentialsButOverrideFromTemplate; -import org.jclouds.googlecomputeengine.config.UserProject; import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.domain.Image; import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.Network; -import org.jclouds.googlecomputeengine.domain.Region; -import org.jclouds.googlecomputeengine.domain.Zone; import org.jclouds.net.domain.IpPermission; -import org.jclouds.rest.AuthorizationException; -import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.base.Optional; import com.google.common.base.Predicate; -import com.google.common.base.Splitter; import com.google.common.base.Supplier; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -94,8 +80,8 @@ import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; -public class GoogleComputeEngineServiceContextModule - extends ComputeServiceAdapterContextModule { +public final class GoogleComputeEngineServiceContextModule + extends ComputeServiceAdapterContextModule { @Override protected void configure() { @@ -103,192 +89,126 @@ public class GoogleComputeEngineServiceContextModule bind(ComputeService.class).to(GoogleComputeEngineService.class); - bind(new TypeLiteral>() {}) - .to(GoogleComputeEngineServiceAdapter.class); + bind(new TypeLiteral>() { + }).to(GoogleComputeEngineServiceAdapter.class); - bind(new TypeLiteral>() {}) - .to(InstanceInZoneToNodeMetadata.class); + bind(new TypeLiteral>() { + }).toInstance(Functions.identity()); - bind(new TypeLiteral>() {}) - .to(MachineTypeInZoneToHardware.class); + bind(new TypeLiteral>() { + }).to(InstanceInZoneToNodeMetadata.class); - bind(new TypeLiteral>() {}) - .to(GoogleComputeEngineImageToImage.class); + bind(new TypeLiteral>() { + }).to(MachineTypeInZoneToHardware.class); - bind(new TypeLiteral>() { - }) - .to(RegionToLocation.class); + bind(new TypeLiteral>() { + }).to(GoogleComputeEngineImageToImage.class); - bind(new TypeLiteral>() {}) - .to(ZoneToLocation.class); + bind(new TypeLiteral>>() { + }).to(FirewallToIpPermission.class); - bind(new TypeLiteral>>() {}) - .to(FirewallToIpPermission.class); + bind(new TypeLiteral>() { + }).to(NetworkToSecurityGroup.class); - bind(new TypeLiteral>() {}) - .to(NetworkToSecurityGroup.class); - - bind(new TypeLiteral>>() {}) - .to(BuildInstanceMetadata.class); + bind(new TypeLiteral>>() { + }).to(BuildInstanceMetadata.class); bind(org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy.class) - .to(PopulateDefaultLoginCredentialsForImageStrategy.class); + .to(PopulateDefaultLoginCredentialsForImageStrategy.class); - bind(org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to( - CreateNodesWithGroupEncodedIntoNameThenAddToSet.class); + bind(org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.class) + .to(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class); bind(TemplateOptions.class).to(GoogleComputeEngineTemplateOptions.class); - bind(new TypeLiteral, Set>>() {}) - .to(OrphanedGroupsFromDeadNodes.class); + bind(new TypeLiteral, Set>>() { + }).to(OrphanedGroupsFromDeadNodes.class); - bind(new TypeLiteral>() {}).to(AllNodesInGroupTerminated.class); + bind(new TypeLiteral>() { + }).to(AllNodesInGroupTerminated.class); - bind(new TypeLiteral>() {}) - .to(CreateNetworkIfNeeded.class); + bind(new TypeLiteral>() { + }).to(CreateNetworkIfNeeded.class); - bind(new TypeLiteral>() {}) - .to(FindNetworkOrCreate.class); + bind(new TypeLiteral>() { + }).to(FindNetworkOrCreate.class); - bind(new TypeLiteral() {}) - .to(GoogleComputeEngineSecurityGroupExtension.class); + bind(SecurityGroupExtension.class).to(GoogleComputeEngineSecurityGroupExtension.class); bind(PrioritizeCredentialsFromTemplate.class).to(UseNodeCredentialsButOverrideFromTemplate.class); - - install(new LocationsFromComputeServiceAdapterModule() {}); - bind(FirewallTagNamingConvention.Factory.class).in(Scopes.SINGLETON); } - @Provides - @Singleton - @Memoized - public Supplier> provideImagesMap( - AtomicReference authException, - final Supplier> images, - @Named(PROPERTY_SESSION_INTERVAL) long seconds) { - return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, - new Supplier>() { - @Override - public Map get() { - return uniqueIndex(images.get(), new Function() { - @Override - public URI apply(org.jclouds.compute.domain.Image input) { - return input.getUri(); - } - }); - } - }, - seconds, TimeUnit.SECONDS); + @Provides @Singleton @Memoized Supplier> imageByUri( + @Memoized final Supplier> imageSupplier, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return memoizeWithExpiration(new Supplier>() { + @Override public Map get() { + ImmutableMap.Builder result = ImmutableMap.builder(); + for (org.jclouds.compute.domain.Image image : imageSupplier.get()) { + result.put(image.getUri(), image); + } + return result.build(); + } + }, seconds, SECONDS); } - @Provides - @Singleton - @Memoized - public Supplier> provideHardwaresMap( - AtomicReference authException, - final Supplier> hardwares, - @Named(PROPERTY_SESSION_INTERVAL) long seconds) { - return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, - new Supplier>() { - @Override - public Map get() { - return uniqueIndex(hardwares.get(), new Function() { - @Override - public URI apply(Hardware input) { - return input.getUri(); - } - }); - } - }, - seconds, TimeUnit.SECONDS); + @Provides @Singleton @Memoized Supplier> hardwareByUri( + @Memoized final Supplier> hardwareSupplier, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return memoizeWithExpiration(new Supplier>() { + @Override public Map get() { + ImmutableMap.Builder result = ImmutableMap.builder(); + for (Hardware hardware : hardwareSupplier.get()) { + result.put(hardware.getUri(), hardware); + } + return result.build(); + } + }, seconds, SECONDS); } - @Provides - @Singleton - @Memoized - public Supplier> provideZones( - AtomicReference authException, - final GoogleComputeEngineApi api, final Function zoneToLocation, - @UserProject final Supplier userProject, - @Named(PROPERTY_SESSION_INTERVAL) long seconds) { - return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, - new Supplier>() { - @Override - public Map get() { - return uniqueIndex(transform(concat(api.getZoneApi(userProject.get()).list()), zoneToLocation), - new Function() { - @Override - public URI apply(Location input) { - return (URI) input.getMetadata().get("selfLink"); - } - }); - } - }, - seconds, TimeUnit.SECONDS); + @Provides @Singleton @Memoized Supplier> locationsByUri( + @Memoized final Supplier> locations, + @Memoized final Supplier> selfLinkToNames, @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return memoizeWithExpiration(new Supplier>() { + @Override public Map get() { + ImmutableMap.Builder result = ImmutableMap.builder(); + for (Location location : locations.get()) { + for (Map.Entry entry : selfLinkToNames.get().entrySet()) { + if (entry.getValue().equals(location.getId())) { + result.put(entry.getKey(), location); + continue; + } + } + } + return result.build(); + } + }, seconds, SECONDS); } - @Provides - @Singleton - @Memoized - public Supplier> provideRegions( - AtomicReference authException, - final GoogleComputeEngineApi api, - @UserProject final Supplier userProject, - @Named(PROPERTY_SESSION_INTERVAL) long seconds) { - return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, - new Supplier>() { - @Override - public Map get() { - return uniqueIndex(concat(api.getRegionApi(userProject.get()).list()), - new Function() { - @Override - public URI apply(Region input) { - return input.selfLink(); - } - }); - } - }, - seconds, TimeUnit.SECONDS); - } - - @Provides - @Singleton - protected LoadingCache networkMap( - CacheLoader in) { + @Provides @Singleton + LoadingCache networkMap(CacheLoader in) { return CacheBuilder.newBuilder().build(in); } - @Override - protected Optional provideImageExtension(Injector i) { + @Override protected Optional provideImageExtension(Injector i) { return Optional.absent(); } - @Override - protected Optional provideSecurityGroupExtension(Injector i) { + @Override protected Optional provideSecurityGroupExtension(Injector i) { return Optional.of(i.getInstance(SecurityGroupExtension.class)); } - @VisibleForTesting - public static final Map toPortableNodeStatus = - ImmutableMap.builder() - .put(Instance.Status.PROVISIONING, NodeMetadata.Status.PENDING) - .put(Instance.Status.STAGING, NodeMetadata.Status.PENDING) - .put(Instance.Status.RUNNING, NodeMetadata.Status.RUNNING) - .put(Instance.Status.STOPPING, NodeMetadata.Status.PENDING) - .put(Instance.Status.STOPPED, NodeMetadata.Status.SUSPENDED) - .put(Instance.Status.TERMINATED, NodeMetadata.Status.TERMINATED).build(); + private static final Map toPortableNodeStatus = + ImmutableMap.builder() + .put(Instance.Status.PROVISIONING, NodeMetadata.Status.PENDING) + .put(Instance.Status.STAGING, NodeMetadata.Status.PENDING) + .put(Instance.Status.RUNNING, NodeMetadata.Status.RUNNING) + .put(Instance.Status.STOPPING, NodeMetadata.Status.PENDING) + .put(Instance.Status.STOPPED, NodeMetadata.Status.SUSPENDED) + .put(Instance.Status.TERMINATED, NodeMetadata.Status.TERMINATED).build(); - @Singleton - @Provides - protected Map toPortableNodeStatus() { + @Provides Map toPortableNodeStatus() { return toPortableNodeStatus; } - - @Singleton - @Provides - @Named(GCE_IMAGE_PROJECTS) - protected List imageProjects(@Named(GCE_IMAGE_PROJECTS) String imageProjects) { - return Splitter.on(',').splitToList(imageProjects); - } } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java index 80b18b1d5f..5d28b63cc0 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java @@ -19,8 +19,6 @@ package org.jclouds.googlecomputeengine.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; -import javax.inject.Singleton; - import org.jclouds.compute.options.TemplateOptions; import com.google.common.base.Function; @@ -29,11 +27,9 @@ import com.google.common.collect.ImmutableMap; /** * Prepares metadata from the provided TemplateOptions */ -@Singleton -public class BuildInstanceMetadata implements Function> { +public final class BuildInstanceMetadata implements Function> { - @Override - public ImmutableMap.Builder apply(TemplateOptions input) { + @Override public ImmutableMap.Builder apply(TemplateOptions input) { ImmutableMap.Builder builder = ImmutableMap.builder(); if (input.getPublicKey() != null) { builder.put("sshKeys", format("%s:%s %s@localhost", checkNotNull(input.getLoginUser(), @@ -42,5 +38,4 @@ public class BuildInstanceMetadata implements Function { - @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) - private Logger logger = Logger.NULL; - private final GoogleComputeEngineApi api; private final Supplier userProject; private final Predicate> operationDonePredicate; diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java index 977c9ab97e..db43000646 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java @@ -47,22 +47,22 @@ public final class InstanceInZoneToNodeMetadata implements Function toPortableNodeStatus; private final GroupNamingConvention nodeNamingConvention; - private final Supplier> images; - private final Supplier> hardwares; - private final Supplier> locations; + private final Supplier> images; + private final Supplier> hardwares; + private final Supplier> locationsByUri; private final FirewallTagNamingConvention.Factory firewallTagNamingConvention; @Inject InstanceInZoneToNodeMetadata(Map toPortableNodeStatus, GroupNamingConvention.Factory namingConvention, - @Memoized Supplier> images, - @Memoized Supplier> hardwares, - @Memoized Supplier> locations, + @Memoized Supplier> images, + @Memoized Supplier> hardwares, + @Memoized Supplier> locationsByUri, FirewallTagNamingConvention.Factory firewallTagNamingConvention) { this.toPortableNodeStatus = toPortableNodeStatus; this.nodeNamingConvention = namingConvention.createWithoutPrefix(); this.images = images; this.hardwares = hardwares; - this.locations = locations; + this.locationsByUri = locationsByUri; this.firewallTagNamingConvention = checkNotNull(firewallTagNamingConvention, "firewallTagNamingConvention"); } @@ -77,12 +77,16 @@ public final class InstanceInZoneToNodeMetadata implements Function imagesMap = images.get(); + Map imagesMap = images.get(); Image image = checkNotNull(imagesMap.get(imageUri), "no image for %s. images: %s", imageUri, diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java index 4ed2a115ef..fe3be1165f 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java @@ -16,13 +16,11 @@ */ package org.jclouds.googlecomputeengine.compute.functions; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Iterables.getOnlyElement; - import java.net.URI; import java.util.Map; +import javax.inject.Inject; + import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.HardwareBuilder; @@ -36,40 +34,31 @@ import org.jclouds.googlecomputeengine.compute.domain.SlashEncodedIds; import org.jclouds.googlecomputeengine.domain.MachineType; import com.google.common.base.Function; -import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; -/** - * Transforms a google compute domain specific machine type to a generic Hardware object. - */ -public class MachineTypeInZoneToHardware implements Function { +public final class MachineTypeInZoneToHardware implements Function { - private final Supplier> locations; + private final Supplier> locationsByUri; - @Inject - public MachineTypeInZoneToHardware(@Memoized Supplier> locations) { - this.locations = locations; + @Inject MachineTypeInZoneToHardware(@Memoized Supplier> locationsByUri) { + this.locationsByUri = locationsByUri; } @Override - public Hardware apply(final MachineTypeInZone input) { - Iterable zonesForMachineType = filter(locations.get().values(), new Predicate() { - @Override - public boolean apply(Location l) { - return l.getId().equals(input.machineType().zone()); - } - }); - - Location location = checkNotNull(getOnlyElement(zonesForMachineType), - "location for %s", - input.machineType().zone()); + public Hardware apply(MachineTypeInZone input) { + URI zoneLink = URI.create( + input.machineType().selfLink().toString().replace("/machineTypes/" + input.machineType().name(), "")); + Location zone = locationsByUri.get().get(zoneLink); + if (zone == null) { + throw new IllegalStateException( + String.format("zone %s not present in %s", zoneLink, locationsByUri.get().keySet())); + } return new HardwareBuilder() .id(SlashEncodedIds.from(input.machineType().zone(), input.machineType().name()).slashEncode()) - .location(location) + .location(zone) .name(input.machineType().name()) .hypervisor("kvm") .processor(new Processor(input.machineType().guestCpus(), 1.0)) diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java index 3301c8f765..09c4a172fe 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java @@ -19,7 +19,6 @@ package org.jclouds.googlecomputeengine.compute.functions; import java.util.Set; import javax.inject.Inject; -import javax.inject.Singleton; import org.jclouds.compute.domain.NodeMetadata; @@ -27,19 +26,16 @@ import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Sets; -@Singleton -public class OrphanedGroupsFromDeadNodes implements Function, Set> { +public final class OrphanedGroupsFromDeadNodes implements Function, Set> { private final Predicate isOrphanedGroupPredicate; - @Inject - public OrphanedGroupsFromDeadNodes(Predicate isOrphanedGroupPredicate) { + @Inject OrphanedGroupsFromDeadNodes(Predicate isOrphanedGroupPredicate) { this.isOrphanedGroupPredicate = isOrphanedGroupPredicate; } - @Override - public Set apply(Set deadNodes) { + @Override public Set apply(Set deadNodes) { Set groups = Sets.newLinkedHashSet(); for (NodeMetadata deadNode : deadNodes) { groups.add(deadNode.getGroup()); @@ -52,6 +48,4 @@ public class OrphanedGroupsFromDeadNodes implements Function { - - @Override - public Location apply(Region input) { - return new LocationBuilder() - .description(input.description()) - .metadata(ImmutableMap.of("selfLink", (Object) checkNotNull(input.selfLink(), "region URI"))) - .id(input.name()) - .scope(LocationScope.REGION) - .parent(GOOGLE_PROVIDER_LOCATION) - .build(); - } -} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java deleted file mode 100644 index b4455b9565..0000000000 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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.googlecomputeengine.compute.functions; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GOOGLE_PROVIDER_LOCATION; - -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; -import org.jclouds.googlecomputeengine.domain.Zone; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; - -/** - * Transforms a google compute domain specific zone to a generic Zone object. - */ -public class ZoneToLocation implements Function { - - @Override - public Location apply(Zone input) { - return new LocationBuilder() - .description(input.description()) - .metadata(ImmutableMap.of("selfLink", (Object) checkNotNull(input.selfLink(), "zone URI"))) - .id(input.name()) - .scope(LocationScope.ZONE) - .parent(GOOGLE_PROVIDER_LOCATION) - .build(); - } -} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java index 9bb670f1da..c6e5f69756 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java @@ -36,7 +36,7 @@ import com.google.common.collect.Lists; /** * Instance options specific to Google Compute Engine. */ -public class GoogleComputeEngineTemplateOptions extends TemplateOptions { +public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { private Optional network = Optional.absent(); private List serviceAccounts = Lists.newArrayList(); diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java index 51e64c0712..1f95582f01 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java @@ -18,10 +18,10 @@ package org.jclouds.googlecomputeengine.config; import static com.google.common.base.Suppliers.compose; import static com.google.inject.name.Names.named; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import java.net.URI; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Named; @@ -31,7 +31,6 @@ import org.jclouds.domain.Credentials; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.compute.domain.SlashEncodedIds; import org.jclouds.googlecomputeengine.domain.Operation; -import org.jclouds.googlecomputeengine.domain.Project; import org.jclouds.googlecomputeengine.handlers.GoogleComputeEngineErrorHandler; import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; import org.jclouds.googlecomputeengine.predicates.RegionOperationDonePredicate; @@ -44,8 +43,6 @@ import org.jclouds.http.annotation.ServerError; import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; import org.jclouds.location.Provider; -import org.jclouds.location.suppliers.ImplicitLocationSupplier; -import org.jclouds.location.suppliers.implicit.FirstZone; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; @@ -57,14 +54,10 @@ import com.google.common.base.Splitter; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; import com.google.inject.Provides; -import com.google.inject.Scopes; import com.google.inject.TypeLiteral; -/** - * Configures the GoogleCompute connection. - */ @ConfiguresHttpApi -public class GoogleComputeEngineHttpApiModule extends HttpApiModule { +public final class GoogleComputeEngineHttpApiModule extends HttpApiModule { public GoogleComputeEngineHttpApiModule() { } @@ -77,7 +70,6 @@ public class GoogleComputeEngineHttpApiModule extends HttpApiModule>>() { }).annotatedWith(named("zone")).to(ZoneOperationDonePredicate.class); - bind(ImplicitLocationSupplier.class).to(FirstZone.class).in(Scopes.SINGLETON); super.configure(); } @@ -88,13 +80,21 @@ public class GoogleComputeEngineHttpApiModule extends HttpApiModule supplyProject(@Provider final Supplier creds, - final GoogleComputeEngineApi api, - AtomicReference authException, - @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + @UserProject Supplier projectName(@Provider final Supplier creds, + final GoogleComputeEngineApi api, + AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, compose(new Function() { public String apply(Credentials in) { @@ -111,17 +111,15 @@ public class GoogleComputeEngineHttpApiModule extends HttpApiModule provideMachineTypeNameToURIFunction(@Provider final Supplier endpoint, - @UserProject final Supplier userProject) { + @Named("machineTypeToURI") Function machineTypeNameToURI( + @Provider final Supplier endpoint, @UserProject final Supplier userProject) { return new Function() { @Override public URI apply(String input) { @@ -135,43 +133,13 @@ public class GoogleComputeEngineHttpApiModule extends HttpApiModule provideNetworkNameToURIFunction(@Provider final Supplier endpoint, - @UserProject final Supplier userProject) { + @Named("networkToURI") Function networkNameToURI(@Provider final Supplier endpoint, + @UserProject final Supplier userProject) { return new Function() { - @Override - public URI apply(String input) { + @Override public URI apply(String input) { return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) .appendPath("/global/networks/").appendPath(input).build(); } }; } - - @Provides - @Singleton - @Named("zoneToURI") - public Function provideZoneNameToURIFunction(@Provider final Supplier endpoint, - @UserProject final Supplier userProject) { - return new Function() { - @Override - public URI apply(String input) { - return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) - .appendPath("/zones/").appendPath(input).build(); - } - }; - } - - @Provides - @Singleton - @Named("regionToURI") - public Function provideRegionNameToURIFunction(@Provider final Supplier endpoint, - @UserProject final Supplier userProject) { - return new Function() { - @Override - public URI apply(String input) { - return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) - .appendPath("/regions/").appendPath(input).build(); - } - }; - } } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineLocationModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineLocationModule.java new file mode 100644 index 0000000000..03d0e9dda7 --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineLocationModule.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.googlecomputeengine.config; + +import static com.google.common.base.Suppliers.compose; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.googlecomputeengine.internal.ListPages.concat; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.collect.Memoized; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.location.config.LocationModule; +import org.jclouds.location.predicates.LocationPredicates; +import org.jclouds.location.reference.LocationConstants; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; +import org.jclouds.location.suppliers.LocationsSupplier; +import org.jclouds.location.suppliers.RegionIdToURISupplier; +import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; +import org.jclouds.location.suppliers.RegionIdsSupplier; +import org.jclouds.location.suppliers.ZoneIdToURISupplier; +import org.jclouds.location.suppliers.ZoneIdsSupplier; +import org.jclouds.location.suppliers.all.ZoneToRegionToProviderOrJustProvider; +import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet; +import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues; +import org.jclouds.location.suppliers.implicit.FirstZone; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.google.inject.Provides; + +/** + * This configures dynamic locations from {@link org.jclouds.googlecomputeengine.features.RegionApi#list}. As the only + * assignable location for nodes are zones, this module does not directly expose regions. Rather, they can be found by + * looking at {@link Location#getParent()} on a zone. + + *

This does not yet support constraining region or zone lists via settings {@linkplain + * LocationConstants#PROPERTY_REGIONS} or {@linkplain LocationConstants#PROPERTY_ZONES}. + */ +public final class GoogleComputeEngineLocationModule extends LocationModule { + + @Override protected void configure() { + super.configure(); + // Unlike EC2, you cannot default GCE instances to a region. Hence, we constrain to zones. + bind(LocationsSupplier.class).to(OnlyZonesLocationSupplier.class); + bind(ImplicitLocationSupplier.class).to(FirstZone.class); + + // Region and zones are derived from the same network request to RegionApi.list + // Using these suppliers will make that consistent and also cache timeout consistently + bind(RegionIdToZoneIdsSupplier.class).to(RegionIdToZoneIdsFromRegionList.class); + bind(RegionIdToURISupplier.class).to(RegionIdToURISupplierFromRegionList.class); + bind(ZoneIdToURISupplier.class).to(ZoneIdToURIFromRegionList.class); + bind(ZoneIdsSupplier.class).to(ZoneIdsFromRegionIdToZoneIdsValues.class); + bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class); + } + + /** Retain the metadata tree, including regions, just don't present anything except zones as assignable. */ + static final class OnlyZonesLocationSupplier implements LocationsSupplier { + // This correctly links parents for zone -> region -> provider. + private final ZoneToRegionToProviderOrJustProvider delegate; + + @Inject OnlyZonesLocationSupplier(ZoneToRegionToProviderOrJustProvider delegate) { + this.delegate = delegate; + } + + @Override public Set get() { + return Sets.filter(delegate.get(), LocationPredicates.isZone()); + } + } + + /** + * Since this is caching a direct api call, we memoize, but short-circuit on any auth exception. This prevents + * excessive errors when things occur in parallel, or as peers on a function graph. + */ + @Provides @Singleton @Memoized Supplier> regions(@UserProject Supplier project, + final GoogleComputeEngineApi api, AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier + .create(authException, compose(new Function>() { + public List apply(String project) { + return ImmutableList.copyOf(concat(api.getRegionApi(project).list())); + } + }, project), seconds, TimeUnit.SECONDS); + } + + @Provides @Singleton @Memoized Supplier> selfLinkToNames( + AtomicReference authException, @Memoized Supplier> regions, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier + .create(authException, compose(new Function, Map>() { + public Map apply(List regions) { + ImmutableMap.Builder selfLinkToName = ImmutableMap.builder(); + for (Region region : regions) { + selfLinkToName.put(region.selfLink(), region.name()); + for (URI zoneSelfLink : region.zones()) { + selfLinkToName.put(zoneSelfLink, toName(zoneSelfLink)); + } + } + return selfLinkToName.build(); + } + }, regions), seconds, TimeUnit.SECONDS); + } + + static final class RegionIdToZoneIdsFromRegionList implements RegionIdToZoneIdsSupplier { + private final Supplier> regions; + + @Inject RegionIdToZoneIdsFromRegionList(@Memoized Supplier> regions) { + this.regions = regions; + } + + @Override public Map>> get() { + ImmutableMap.Builder>> result = ImmutableMap.builder(); + for (org.jclouds.googlecomputeengine.domain.Region region : regions.get()) { + ImmutableSet.Builder zoneIds = ImmutableSet.builder(); + for (URI uri : region.zones()) { + zoneIds.add(toName(uri)); + } + result.put(region.name(), Suppliers.>ofInstance(zoneIds.build())); + } + return result.build(); + } + } + + static final class RegionIdToURISupplierFromRegionList implements RegionIdToURISupplier { + private final Supplier> regions; + + @Inject RegionIdToURISupplierFromRegionList(@Memoized Supplier> regions) { + this.regions = regions; + } + + @Override public Map> get() { + ImmutableMap.Builder> result = ImmutableMap.builder(); + for (org.jclouds.googlecomputeengine.domain.Region region : regions.get()) { + result.put(region.name(), Suppliers.ofInstance(region.selfLink())); + } + return result.build(); + } + } + + static final class ZoneIdToURIFromRegionList implements ZoneIdToURISupplier { + private final Supplier> regions; + + @Inject ZoneIdToURIFromRegionList(@Memoized Supplier> regions) { + this.regions = regions; + } + + @Override public Map> get() { + ImmutableMap.Builder> result = ImmutableMap.builder(); + for (Region region : regions.get()) { + for (URI input : region.zones()) { + result.put(toName(input), Suppliers.ofInstance(input)); + } + } + return result.build(); + } + } + + private static String toName(URI link) { + String path = link.getPath(); + return path.substring(path.lastIndexOf('/') + 1); + } +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java index c0a7883be7..815ccf1585 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java @@ -55,7 +55,7 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class); } - @Provides @Singleton public Map typeAdapters() { + @Provides @Singleton Map typeAdapters() { return new ImmutableMap.Builder() .put(InstanceTemplate.class, new InstanceTemplateTypeAdapter()) .put(FirewallOptions.class, new FirewallOptionsTypeAdapter()) @@ -63,11 +63,11 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { } // TODO: change jclouds core to use collaborative set bindings - @Provides @Singleton public Set typeAdapterFactories() { + @Provides @Singleton Set typeAdapterFactories() { return ImmutableSet.of(new MetadataTypeAdapter()); } - private static class InstanceTemplateTypeAdapter implements JsonSerializer { + private static final class InstanceTemplateTypeAdapter implements JsonSerializer { @Override public JsonElement serialize(InstanceTemplate src, Type typeOfSrc, JsonSerializationContext context) { InstanceTemplateInternal template = new InstanceTemplateInternal(src); @@ -96,7 +96,7 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { return instance; } - private static class InstanceTemplateInternal extends InstanceTemplate { + private static final class InstanceTemplateInternal extends InstanceTemplate { private InstanceTemplateInternal(InstanceTemplate template) { machineType(template.machineType()); name(template.name()); @@ -108,11 +108,7 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { } } - private static class MetadataTypeAdapter extends SubtypeAdapterFactory { - - private MetadataTypeAdapter() { - super(Metadata.class); - } + private static final class MetadataTypeAdapter extends TypeAdapter implements TypeAdapterFactory { @Override public void write(JsonWriter out, Metadata src) throws IOException { out.beginObject(); @@ -167,9 +163,16 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { in.endObject(); return Metadata.create(fingerprint, builder.build()); } + + @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { + if (!(Metadata.class.isAssignableFrom(typeToken.getRawType()))) { + return null; + } + return (TypeAdapter) this; + } } - private static class FirewallOptionsTypeAdapter implements JsonSerializer { + private static final class FirewallOptionsTypeAdapter implements JsonSerializer { @Override public JsonElement serialize(FirewallOptions src, Type typeOfSrc, JsonSerializationContext context) { JsonObject firewall = new JsonObject(); @@ -199,7 +202,7 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { } } - private static class RouteOptionsTypeAdapter implements JsonSerializer { + private static final class RouteOptionsTypeAdapter implements JsonSerializer { @Override public JsonElement serialize(RouteOptions src, Type typeOfSrc, JsonSerializationContext context) { JsonObject route = new JsonObject(); @@ -244,19 +247,4 @@ public final class GoogleComputeEngineParserModule extends AbstractModule { } return array; } - - private abstract static class SubtypeAdapterFactory extends TypeAdapter implements TypeAdapterFactory { - private final Class baseClass; - - private SubtypeAdapterFactory(Class baseClass) { - this.baseClass = baseClass; - } - - @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { - if (!(baseClass.isAssignableFrom(typeToken.getRawType()))) { - return null; - } - return (TypeAdapter) this; - } - } } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java index 1eb3f4d9da..65c0723db2 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java @@ -28,7 +28,6 @@ import org.jclouds.collect.Memoized; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.config.UserProject; import org.jclouds.googlecomputeengine.domain.Operation; -import org.jclouds.googlecomputeengine.domain.Region; import com.google.common.base.Predicate; import com.google.common.base.Supplier; @@ -36,19 +35,19 @@ import com.google.common.base.Supplier; public final class RegionOperationDonePredicate implements Predicate> { private final GoogleComputeEngineApi api; private final Supplier project; - private final Supplier> regions; + private final Supplier> selfLinkToName; @Inject RegionOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project, - @Memoized Supplier> regions) { + @Memoized Supplier> selfLinkToName) { this.api = api; this.project = project; - this.regions = regions; + this.selfLinkToName = selfLinkToName; } @Override public boolean apply(AtomicReference input) { checkNotNull(input.get(), "input"); URI region = checkNotNull(input.get().region(), "region of %s", input.get()); - String locationId = checkNotNull(regions.get().get(region), "location of %s", region).id(); + String locationId = checkNotNull(selfLinkToName.get().get(region), "location of %s", region); Operation current = api.getRegionOperationApi(project.get(), locationId).get(input.get().name()); switch (current.status()) { case DONE: diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java index 9c727ede44..0081d30543 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java @@ -23,7 +23,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import org.jclouds.collect.Memoized; -import org.jclouds.domain.Location; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.config.UserProject; import org.jclouds.googlecomputeengine.domain.Operation; @@ -39,19 +38,19 @@ public final class ZoneOperationDonePredicate implements Predicate project; - private final Supplier> zones; + private final Supplier> selfLinkToName; @Inject ZoneOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project, - @Memoized Supplier> zones) { + @Memoized Supplier> selfLinkToName) { this.api = api; this.project = project; - this.zones = zones; + this.selfLinkToName = selfLinkToName; } @Override public boolean apply(AtomicReference input) { checkNotNull(input.get(), "input"); URI zone = checkNotNull(input.get().zone(), "zone of %s", input.get()); - String locationId = checkNotNull(zones.get().get(zone), "location of %s", zone).getId(); + String locationId = checkNotNull(selfLinkToName.get().get(zone), "location of %s", zone); Operation current = api.getZoneOperationApi(project.get(), locationId).get(input.get().name()); switch (current.status()) { case DONE: diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadataTest.java similarity index 55% rename from providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java rename to providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadataTest.java index 28b870393b..d7d52eb2c1 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineProviderMetadataTest.java @@ -16,27 +16,19 @@ */ package org.jclouds.googlecomputeengine; -import static org.jclouds.reflect.Reflection2.typeToken; - -import org.jclouds.View; -import org.jclouds.apis.internal.BaseApiMetadataTest; -import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.providers.internal.BaseProviderMetadataTest; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableSet; -import com.google.common.reflect.TypeToken; - /** - * Tests that GoogleComputeApiMetadata is properly registered in ServiceLoader + * Tests that GoogleComputeProviderMetadata is properly registered in ServiceLoader *

*

- * META-INF/services/org.jclouds.apis.ApiMetadata
+ * META-INF/services/org.jclouds.providers.ProviderMetadata
  * 
*/ -@Test(groups = "unit", testName = "GoogleComputeApiMetadataTest") -public class GoogleComputeEngineApiMetadataTest extends BaseApiMetadataTest { - public GoogleComputeEngineApiMetadataTest() { - super(new GoogleComputeEngineApiMetadata(), - ImmutableSet.>of(typeToken(ComputeServiceContext.class))); +@Test(groups = "unit", testName = "GoogleComputeProviderMetadataTest") +public class GoogleComputeEngineProviderMetadataTest extends BaseProviderMetadataTest { + public GoogleComputeEngineProviderMetadataTest() { + super(new GoogleComputeEngineProviderMetadata(), new GoogleComputeEngineApiMetadata()); } } diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java index 0fc17713a4..3018c1ed15 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java @@ -16,11 +16,15 @@ */ package org.jclouds.googlecomputeengine.compute; +import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Iterables.getOnlyElement; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_BOOT_DISK_SUFFIX; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS; +import static org.jclouds.googlecomputeengine.domain.Instance.Status.RUNNING; +import static org.jclouds.googlecomputeengine.domain.Instance.Status.TERMINATED; import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_REQUEST; import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_RESPONSE; import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_CENTOS_IMAGES_REQUEST; @@ -40,38 +44,33 @@ import static org.jclouds.googlecomputeengine.features.MachineTypeApiExpectTest. import static org.jclouds.googlecomputeengine.features.NetworkApiExpectTest.GET_NETWORK_REQUEST; import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_REQUEST; import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_RESPONSE; -import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_REQ; -import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_RESPONSE; -import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_SHORT_RESPONSE; +import static org.jclouds.googlecomputeengine.features.RegionApiExpectTest.LIST_REGIONS_REQ; import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_REQUEST; import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_RESPONSE; import static org.jclouds.util.Strings2.toStringAndClose; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import java.io.IOException; import java.util.List; import java.util.Properties; import java.util.Set; -import javax.ws.rs.core.MediaType; - import org.jclouds.compute.ComputeService; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; import org.jclouds.domain.Location; +import org.jclouds.domain.LocationScope; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; -import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.features.InstanceApiExpectTest; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineServiceExpectTest; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; -import org.jclouds.util.Strings2; import org.testng.annotations.Test; -import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -82,11 +81,11 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin private HttpRequest INSERT_NETWORK_REQUEST = HttpRequest .builder() .method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/networks") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/networks") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN) .payload(payloadFromStringWithContentType("{\"name\":\"jclouds-test\",\"IPv4Range\":\"10.0.0.0/8\"}", - MediaType.APPLICATION_JSON)) + APPLICATION_JSON)) .build(); private HttpResponse GET_NETWORK_RESPONSE = HttpResponse.builder().statusCode(200) @@ -100,33 +99,39 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin " \"description\": \"test network\",\n" + " \"IPv4Range\": \"10.0.0.0/8\",\n" + " \"gatewayIPv4\": \"10.0.0.1\"\n" + - "}", MediaType.APPLICATION_JSON)).build(); + "}", APPLICATION_JSON)).build(); - private HttpResponse SUCESSFULL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) + private HttpResponse SUCCESSFUL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) .payload(payloadFromResource("/operation.json")).build(); private HttpRequest SET_TAGS_REQUEST = HttpRequest.builder() .method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setTags") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/instances/test-1/setTags") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN) .payload(payloadFromStringWithContentType("{\"items\":[\"aTag\"],\"fingerprint\":\"abcd\"}", - MediaType.APPLICATION_JSON)) + APPLICATION_JSON)) .build(); private HttpResponse SET_TAGS_RESPONSE = HttpResponse.builder().statusCode(200) .payload(payloadFromResource("/operation.json")).build(); private HttpResponse getInstanceResponseForInstanceAndNetworkAndStatus(String instanceName, String networkName, - String status) throws - IOException { + String status) throws IOException { return HttpResponse.builder().statusCode(200) .payload(payloadFromStringWithContentType( replaceInstanceNameNetworkAndStatusOnResource("/instance_get.json", instanceName, networkName, status), - "application/json")).build(); + APPLICATION_JSON)).build(); } + /** Reduce work implementing this test, by only using one region, zone! */ + private final HttpResponse singleRegionSingleZoneResponse = HttpResponse.builder().statusCode(200).payload( + "{\"items\":[" + payloadFromResource("/region_get.json").getRawContent().toString() + .replace("\"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b\"", "") + + "]}") + .build(); + private HttpResponse getListInstancesResponseForSingleInstanceAndNetworkAndStatus(String instanceName, String networkName, String status) { @@ -134,32 +139,31 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin .payload(payloadFromStringWithContentType( replaceInstanceNameNetworkAndStatusOnResource("/instance_list.json", instanceName, networkName, status), - "application/json")).build(); + APPLICATION_JSON)).build(); } private HttpResponse getDiskResponseForInstance(String instanceName) { return HttpResponse.builder().statusCode(200) .payload(payloadFromStringWithContentType( - replaceDiskNameOnResource("/disk_get.json", instanceName + "-" + GCE_BOOT_DISK_SUFFIX), - "application/json")).build(); + replaceDiskNameOnResource("/disk_get.json", instanceName + "-" + GCE_BOOT_DISK_SUFFIX), + APPLICATION_JSON)).build(); } private String replaceDiskNameOnResource(String resourceName, String diskName) { try { - return Strings2.toStringAndClose(this.getClass().getResourceAsStream(resourceName)) - .replace("testimage1", diskName); + return toStringAndClose(this.getClass().getResourceAsStream(resourceName)).replace("testimage1", diskName); } catch (IOException e) { - throw Throwables.propagate(e); + throw propagate(e); } } private String replaceInstanceNameNetworkAndStatusOnResource(String resourceName, String instanceName, String networkName, String status) { try { - return Strings2.toStringAndClose(this.getClass().getResourceAsStream(resourceName)).replace("test-0", - instanceName).replace("default", networkName).replace("RUNNING", status); + return toStringAndClose(this.getClass().getResourceAsStream(resourceName)).replace("test-0", instanceName) + .replace("default", networkName).replace("RUNNING", status); } catch (IOException e) { - throw Throwables.propagate(e); + throw propagate(e); } } @@ -167,31 +171,29 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin return HttpRequest .builder() .method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/disks") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN) .payload(payloadFromStringWithContentType("{\"name\":\"" + instanceName + "-" + GCE_BOOT_DISK_SUFFIX + "\"," + "\"sizeGb\":10," + "\"sourceImage\":\"https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140718\"}", - MediaType.APPLICATION_JSON)).build(); + APPLICATION_JSON)).build(); } private HttpRequest getDiskRequestForInstance(String instanceName) { return HttpRequest .builder() .method("GET") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/" - + instanceName + "-" + GCE_BOOT_DISK_SUFFIX) - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/disks/" + instanceName + "-" + GCE_BOOT_DISK_SUFFIX) + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); } private HttpRequest createInstanceRequestForInstance(String instanceName, String groupName, String networkName, String publicKey) { return HttpRequest.builder().method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances") - .addHeader("Accept", "application/json").addHeader("Authorization", "Bearer " + TOKEN).payload( + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/instances") + .addHeader("Accept", APPLICATION_JSON).addHeader("Authorization", "Bearer " + TOKEN).payload( payloadFromStringWithContentType("{\"name\":\"" + instanceName + "\",\"machineType\":\"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/f1-micro\",\"serviceAccounts\":[],\"disks\":[{\"type\":\"PERSISTENT\",\"mode\":\"READ_WRITE\",\"source\":\"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/" + instanceName + "-" + GCE_BOOT_DISK_SUFFIX @@ -200,29 +202,28 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin + "\",\"accessConfigs\":[{\"type\":\"ONE_TO_ONE_NAT\"}]}],\"metadata\":{\"kind\":\"compute#metadata\",\"items\":[{\"key\":\"sshKeys\",\"value\":\"jclouds:" + publicKey + " jclouds@localhost\"},{\"key\":\"jclouds-group\",\"value\":\"" + groupName + "\"},{\"key\":\"jclouds-image\",\"value\":\"https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140718\"},{\"key\":\"jclouds-delete-boot-disk\",\"value\":\"true\"}]}}", - MediaType.APPLICATION_JSON)).build(); + APPLICATION_JSON)).build(); } private HttpRequest getInstanceRequestForInstance(String instanceName) { return HttpRequest .builder() .method("GET") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/" + instanceName) - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/instances/" + instanceName) + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); } - @Override protected Properties setupProperties() { Properties overrides = super.setupProperties(); overrides.put("google-compute-engine.identity", "myproject"); overrides.put(GCE_IMAGE_PROJECTS, "debian-cloud,centos-cloud"); try { - overrides.put("google-compute-engine.credential", toStringAndClose(getClass().getResourceAsStream("/testpk.pem"))); + overrides.put("google-compute-engine.credential", + toStringAndClose(this.getClass().getResourceAsStream("/testpk.pem"))); } catch (IOException e) { - Throwables.propagate(e); + propagate(e); } return overrides; } @@ -247,7 +248,7 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin builder() .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE) .put(GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE) - .put(LIST_ZONES_REQ, LIST_ZONES_RESPONSE) + .put(LIST_REGIONS_REQ, singleRegionSingleZoneResponse) .put(LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE) .put(LIST_DEBIAN_IMAGES_REQUEST, LIST_DEBIAN_IMAGES_RESPONSE) .put(LIST_CENTOS_IMAGES_REQUEST, LIST_CENTOS_IMAGES_RESPONSE) @@ -265,7 +266,7 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin Hardware fastest = client.templateBuilder().fastest().build().getHardware(); assertNotNull(fastest); - assertEquals(client.listHardwareProfiles().size(), 5); + assertEquals(client.listHardwareProfiles().size(), 3); Template toMatch = client.templateBuilder() .imageId(template.getImage().getId()) @@ -278,23 +279,20 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin HttpRequest deleteNodeRequest = HttpRequest.builder() .method("DELETE") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-delete-networks") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/instances/test-delete-networks") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpRequest deleteFirewallRequest = HttpRequest.builder() .method("DELETE") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/firewalls/jclouds-test-delete") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpRequest getNetworkRequest = HttpRequest.builder() .method("GET") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/global/networks/jclouds-test-delete") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/networks/jclouds-test-delete") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpResponse getNetworkResponse = HttpResponse.builder().statusCode(200) @@ -302,9 +300,8 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin HttpRequest listFirewallsRequest = HttpRequest.builder() .method("GET") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/global/firewalls") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/firewalls") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpResponse listFirewallsResponse = HttpResponse.builder().statusCode(200) @@ -312,23 +309,21 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin HttpRequest deleteNetworkReqquest = HttpRequest.builder() .method("DELETE") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/global/networks/jclouds-test-delete") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/networks/jclouds-test-delete") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpRequest deleteDiskRequest = HttpRequest.builder() .method("DELETE") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/test") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/disks/test") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); List orderedRequests = ImmutableList.builder() .add(requestForScopes(COMPUTE_READONLY_SCOPE)) .add(GET_PROJECT_REQUEST) .add(getInstanceRequestForInstance("test-delete-networks")) - .add(LIST_ZONES_REQ) + .add(LIST_REGIONS_REQ) .add(LIST_MACHINE_TYPES_REQUEST) .add(LIST_PROJECT_IMAGES_REQUEST) .add(LIST_DEBIAN_IMAGES_REQUEST) @@ -349,56 +344,43 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin .add(GET_GLOBAL_OPERATION_REQUEST) .build(); - List orderedResponses = ImmutableList.builder() .add(TOKEN_RESPONSE) .add(GET_PROJECT_RESPONSE) - .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance - .Status.RUNNING.name())) - .add(LIST_ZONES_SHORT_RESPONSE) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", RUNNING.name())) + .add(singleRegionSingleZoneResponse) .add(LIST_MACHINE_TYPES_RESPONSE) .add(LIST_PROJECT_IMAGES_RESPONSE) .add(LIST_DEBIAN_IMAGES_RESPONSE) .add(LIST_CENTOS_IMAGES_RESPONSE) - .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance - .Status.RUNNING.name())) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", RUNNING.name())) .add(TOKEN_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_ZONE_OPERATION_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_ZONE_OPERATION_RESPONSE) - .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance - .Status.TERMINATED.name())) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", TERMINATED.name())) .add(getListInstancesResponseForSingleInstanceAndNetworkAndStatus("test-delete-networks", - "test-network", Instance - .Status.TERMINATED.name())) + "test-network", TERMINATED.name())) .add(getNetworkResponse) .add(listFirewallsResponse) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_GLOBAL_OPERATION_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_GLOBAL_OPERATION_RESPONSE) .build(); ComputeService client = orderedRequestsSendResponses(orderedRequests, orderedResponses); client.destroyNode("us-central1-a/test-delete-networks"); - } - public void testListLocationsWhenResponseIs2xx() throws Exception { + public void listAssignableLocations() throws Exception { ImmutableMap requestResponseMap = ImmutableMap. builder() .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE) .put(GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE) - .put(LIST_ZONES_REQ, LIST_ZONES_RESPONSE) - .put(LIST_INSTANCES_REQUEST, LIST_INSTANCES_RESPONSE) - .put(LIST_CENTRAL1B_INSTANCES_REQUEST, LIST_CENTRAL1B_INSTANCES_RESPONSE) - .put(LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE) - .put(LIST_DEBIAN_IMAGES_REQUEST, LIST_DEBIAN_IMAGES_RESPONSE) - .put(LIST_CENTOS_IMAGES_REQUEST, LIST_CENTOS_IMAGES_RESPONSE) - .put(LIST_MACHINE_TYPES_REQUEST, LIST_MACHINE_TYPES_RESPONSE) - .put(LIST_CENTRAL1B_MACHINE_TYPES_REQUEST, LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE) + .put(LIST_REGIONS_REQ, singleRegionSingleZoneResponse) .build(); ComputeService apiWhenServersExist = requestsSendResponses(requestResponseMap); @@ -406,8 +388,38 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin Set locations = apiWhenServersExist.listAssignableLocations(); assertNotNull(locations); - assertEquals(locations.size(), 2); - assertEquals(locations.iterator().next().getId(), "us-central1-a"); + assertEquals(locations.size(), 1); + Location firstZone = locations.iterator().next(); + assertEquals(firstZone.getId(), "us-central1-a"); + assertEquals(firstZone.getDescription(), "us-central1-a"); + assertEquals(firstZone.getScope(), LocationScope.ZONE); + + assertEquals(firstZone.getParent().getId(), "us-central1"); + assertEquals(firstZone.getParent().getDescription(), "us-central1"); + assertEquals(firstZone.getParent().getScope(), LocationScope.REGION); + + // Google intentionally does not document locations! + assertTrue(firstZone.getIso3166Codes().isEmpty()); + assertTrue(firstZone.getParent().getIso3166Codes().isEmpty()); + } + + public void listNodes() throws Exception { + + ImmutableMap requestResponseMap = ImmutableMap. + builder() + .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE) + .put(GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE) + .put(LIST_REGIONS_REQ, singleRegionSingleZoneResponse) + .put(LIST_INSTANCES_REQUEST, LIST_INSTANCES_RESPONSE) + .put(LIST_CENTRAL1B_INSTANCES_REQUEST, LIST_CENTRAL1B_INSTANCES_RESPONSE) + .put(LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE) + .put(LIST_DEBIAN_IMAGES_REQUEST, LIST_DEBIAN_IMAGES_RESPONSE) + .put(LIST_CENTOS_IMAGES_REQUEST, LIST_CENTOS_IMAGES_RESPONSE) + .put(LIST_MACHINE_TYPES_REQUEST, LIST_MACHINE_TYPES_RESPONSE) + .put(LIST_CENTRAL1B_MACHINE_TYPES_REQUEST, LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE) + .build(); + + ComputeService apiWhenServersExist = requestsSendResponses(requestResponseMap); assertNotNull(apiWhenServersExist.listNodes()); assertEquals(apiWhenServersExist.listNodes().size(), 1); @@ -415,54 +427,52 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin assertEquals(apiWhenServersExist.listNodes().iterator().next().getName(), "test-0"); } - @Test(dependsOnMethods = "testListLocationsWhenResponseIs2xx") + @Test public void testCreateNodeWhenNetworkNorFirewallExistDoesNotExist() throws RunNodesException, IOException { - String payload = Strings2.toStringAndClose(InstanceApiExpectTest.class.getResourceAsStream("/instance_get.json")); + String payload = toStringAndClose(InstanceApiExpectTest.class.getResourceAsStream("/instance_get.json")); payload = payload.replace("test-0", "test-1"); HttpResponse getInstanceResponse = HttpResponse.builder().statusCode(200) - .payload(payloadFromStringWithContentType(payload, "application/json")).build(); + .payload(payloadFromStringWithContentType(payload, APPLICATION_JSON)).build(); HttpRequest getFirewallRequest = HttpRequest .builder() .method("GET") - .endpoint("https://www.googleapis" + - ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test-port-22") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/firewalls/jclouds-test-port-22") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN).build(); HttpRequest insertFirewallRequest = HttpRequest .builder() .method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/global/firewalls") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN) .payload(payloadFromStringWithContentType("{\"name\":\"jclouds-test-port-22\",\"network\":\"https://www.googleapis" + ".com/compute/v1/projects/myproject/global/networks/jclouds-test\"," + "\"sourceRanges\":[\"10.0.0.0/8\",\"0.0.0.0/0\"],\"sourceTags\":[\"aTag\"],\"targetTags\":[\"jclouds-test-port-22\"],\"allowed\":[{\"IPProtocol\":\"tcp\"," + "\"ports\":[\"22\"]}," + "{\"IPProtocol\":\"udp\",\"ports\":[\"22\"]}]}", - MediaType.APPLICATION_JSON)) + APPLICATION_JSON)) .build(); HttpRequest setTagsRequest = HttpRequest .builder() .method("POST") - .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setTags") - .addHeader("Accept", "application/json") + .endpoint(BASE_URL + "/myproject/zones/us-central1-a/instances/test-1/setTags") + .addHeader("Accept", APPLICATION_JSON) .addHeader("Authorization", "Bearer " + TOKEN) .payload(payloadFromStringWithContentType("{\"items\":[\"jclouds-test-port-22\"],\"fingerprint\":\"abcd\"}", - MediaType.APPLICATION_JSON)) + APPLICATION_JSON)) .build(); List orderedRequests = ImmutableList.builder() .add(requestForScopes(COMPUTE_READONLY_SCOPE)) .add(GET_PROJECT_REQUEST) - .add(LIST_ZONES_REQ) + .add(LIST_REGIONS_REQ) .add(LIST_PROJECT_IMAGES_REQUEST) .add(LIST_DEBIAN_IMAGES_REQUEST) .add(LIST_CENTOS_IMAGES_REQUEST) - .add(LIST_ZONES_REQ) .add(LIST_MACHINE_TYPES_REQUEST) .add(GET_NETWORK_REQUEST) .add(GET_NETWORK_REQUEST) @@ -474,10 +484,6 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin .add(insertFirewallRequest) .add(GET_GLOBAL_OPERATION_REQUEST) .add(LIST_INSTANCES_REQUEST) - .add(LIST_MACHINE_TYPES_REQUEST) - .add(LIST_PROJECT_IMAGES_REQUEST) - .add(LIST_DEBIAN_IMAGES_REQUEST) - .add(LIST_CENTOS_IMAGES_REQUEST) .add(createDiskRequestForInstance("test-1")) .add(GET_ZONE_OPERATION_REQUEST) .add(getDiskRequestForInstance("test-1")) @@ -497,43 +503,37 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin List orderedResponses = ImmutableList.builder() .add(TOKEN_RESPONSE) .add(GET_PROJECT_RESPONSE) - .add(LIST_ZONES_SHORT_RESPONSE) + .add(singleRegionSingleZoneResponse) .add(LIST_PROJECT_IMAGES_RESPONSE) .add(LIST_DEBIAN_IMAGES_RESPONSE) .add(LIST_CENTOS_IMAGES_RESPONSE) - .add(LIST_ZONES_SHORT_RESPONSE) .add(LIST_MACHINE_TYPES_RESPONSE) .add(HttpResponse.builder().statusCode(404).build()) .add(HttpResponse.builder().statusCode(404).build()) .add(TOKEN_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_GLOBAL_OPERATION_RESPONSE) .add(GET_NETWORK_RESPONSE) .add(HttpResponse.builder().statusCode(404).build()) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_GLOBAL_OPERATION_RESPONSE) .add(LIST_INSTANCES_RESPONSE) - .add(LIST_MACHINE_TYPES_RESPONSE) - .add(LIST_PROJECT_IMAGES_RESPONSE) - .add(LIST_DEBIAN_IMAGES_RESPONSE) - .add(LIST_CENTOS_IMAGES_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_ZONE_OPERATION_RESPONSE) .add(getDiskResponseForInstance("test-1")) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(GET_ZONE_OPERATION_RESPONSE) .add(getInstanceResponse) .add(SET_TAGS_RESPONSE) .add(GET_ZONE_OPERATION_RESPONSE) .add(getInstanceResponse) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .add(LIST_PROJECT_IMAGES_RESPONSE) .add(LIST_DEBIAN_IMAGES_RESPONSE) .add(LIST_CENTOS_IMAGES_RESPONSE) - .add(SUCESSFULL_OPERATION_RESPONSE) + .add(SUCCESSFUL_OPERATION_RESPONSE) .build(); - ComputeService computeService = orderedRequestsSendResponses(orderedRequests, orderedResponses); GoogleComputeEngineTemplateOptions options = computeService.templateOptions().as(GoogleComputeEngineTemplateOptions.class); diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java index 7d5b4fb556..2b69bdcd79 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java @@ -157,9 +157,9 @@ public class InstanceInZoneToNodeMetadataTest { private InstanceInZoneToNodeMetadata createNodeParser(final Set hardware, final Set images, final Set locations, final String groupName) { - Supplier> locationSupplier = new Supplier>() { + Supplier> locationSupplier = new Supplier>() { @Override - public Map get() { + public Map get() { return Maps.uniqueIndex(locations, new Function() { @Override public URI apply(final Location input) { @@ -169,9 +169,9 @@ public class InstanceInZoneToNodeMetadataTest { } }; - Supplier> hardwareSupplier = new Supplier>() { + Supplier> hardwareSupplier = new Supplier>() { @Override - public Map get() { + public Map get() { return Maps.uniqueIndex(hardware, new Function() { @Override public URI apply(final Hardware input) { @@ -181,9 +181,9 @@ public class InstanceInZoneToNodeMetadataTest { } }; - Supplier> imageSupplier = new Supplier>() { + Supplier> imageSupplier = new Supplier>() { @Override - public Map get() { + public Map get() { return Maps.uniqueIndex(images, new Function() { @Override public URI apply(final Image input) { diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java index cae3432e23..cb48943dfb 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java @@ -51,13 +51,13 @@ public class OrphanedGroupsFromDeadNodesTest { @Test public void testDetectsAllOrphanedGroupsWhenAllNodesTerminated() { - Set deadNodesGroup1 = (Set) ImmutableSet.builder() + Set deadNodesGroup1 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); - Set deadNodesGroup2 = (Set) ImmutableSet.builder() + Set deadNodesGroup2 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.TERMINATED)).build(); - Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); ComputeService mock = createMock(ComputeService.class); expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) @@ -80,13 +80,13 @@ public class OrphanedGroupsFromDeadNodesTest { @Test public void testDetectsAllOrphanedGroupsWhenSomeNodesTerminatedAndOtherMissing() { - Set deadNodesGroup1 = (Set) ImmutableSet.builder() + Set deadNodesGroup1 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); - Set deadNodesGroup2 = (Set) ImmutableSet.builder() + Set deadNodesGroup2 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.TERMINATED)).build(); - Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); ComputeService mock = createMock(ComputeService.class); expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) @@ -109,13 +109,13 @@ public class OrphanedGroupsFromDeadNodesTest { @Test public void testDetectsAllOrphanedGroupsWhenSomeNodesAreAlive() { - Set deadNodesGroup1 = (Set) ImmutableSet.builder() + Set deadNodesGroup1 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); - Set deadNodesGroup2 = (Set) ImmutableSet.builder() + Set deadNodesGroup2 = (Set) ImmutableSet.builder() .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.RUNNING)).build(); - Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); ComputeService mock = createMock(ComputeService.class); expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java index eb6d0fedde..84a8a2d623 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java @@ -232,5 +232,4 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { // we don't really care about any exception here, so just delete away. } } - } diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java index 4ede7f6313..1ab4e0ff83 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java @@ -51,16 +51,13 @@ public class RegionApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { .payload(staticPayloadFromResource("/region_list.json")).build(); public void testGetRegionResponseIs2xx() throws Exception { - - HttpResponse operationResponse = HttpResponse.builder().statusCode(200) .payload(payloadFromResource("/region_get.json")).build(); RegionApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE, GET_REGION_REQ, operationResponse).getRegionApi("myproject"); - assertEquals(api.get("us-central1"), - new ParseRegionTest().expected()); + assertEquals(api.get("us-central1"), new ParseRegionTest().expected()); } public void testGetRegionResponseIs4xx() throws Exception { diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java index e58c5f6747..26f5bf3606 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java @@ -45,14 +45,14 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.ws.rs.core.MediaType; -import org.jclouds.apis.ApiMetadata; import org.jclouds.crypto.Crypto; -import org.jclouds.googlecomputeengine.GoogleComputeEngineApiMetadata; +import org.jclouds.googlecomputeengine.GoogleComputeEngineProviderMetadata; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.io.Payload; import org.jclouds.oauth.v2.OAuthConstants; import org.jclouds.oauth.v2.config.OAuthProperties; +import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.internal.BaseRestApiExpectTest; import org.jclouds.ssh.SshKeys; @@ -85,49 +85,49 @@ public class BaseGoogleComputeEngineExpectTest extends BaseRestApiExpectTest< " \"expires_in\" : 3600\n" + "}")).build(); - protected String openSshKey; + private final KeyPair keyPair; + protected final String openSshKey; - - public BaseGoogleComputeEngineExpectTest() { + protected BaseGoogleComputeEngineExpectTest() { provider = "google-compute-engine"; + try { + KeyFactory keyfactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyfactory + .generatePrivate(privateKeySpec(ByteSource.wrap(PRIVATE_KEY.getBytes(UTF_8)))); + PublicKey publicKey = keyfactory.generatePublic(publicKeySpec(ByteSource.wrap(PUBLIC_KEY.getBytes(UTF_8)))); + keyPair = new KeyPair(publicKey, privateKey); + openSshKey = SshKeys.encodeAsOpenSSH(RSAPublicKey.class.cast(publicKey)); + } catch (NoSuchAlgorithmException e) { + throw propagate(e); + } catch (InvalidKeySpecException e) { + throw propagate(e); + } catch (IOException e) { + throw propagate(e); + } } - @Override protected ApiMetadata createApiMetadata(){ - return new GoogleComputeEngineApiMetadata(); + @Override protected ProviderMetadata createProviderMetadata(){ + return new GoogleComputeEngineProviderMetadata(); } - @Override - protected Module createModule() { + @Override protected Module createModule() { return new Module() { @Override public void configure(Binder binder) { // Predictable time binder.bind(new TypeLiteral>() {}).toInstance(Suppliers.ofInstance(0L)); - try { - KeyFactory keyfactory = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = keyfactory.generatePrivate(privateKeySpec(ByteSource.wrap( - PRIVATE_KEY.getBytes(UTF_8)))); - PublicKey publicKey = keyfactory.generatePublic(publicKeySpec(ByteSource.wrap(PUBLIC_KEY.getBytes(UTF_8)))); - KeyPair keyPair = new KeyPair(publicKey, privateKey); - openSshKey = SshKeys.encodeAsOpenSSH(RSAPublicKey.class.cast(publicKey)); - final Crypto crypto = createMock(Crypto.class); - KeyPairGenerator rsaKeyPairGenerator = createMock(KeyPairGenerator.class); - final SecureRandom secureRandom = createMock(SecureRandom.class); - expect(crypto.rsaKeyPairGenerator()).andReturn(rsaKeyPairGenerator).anyTimes(); - rsaKeyPairGenerator.initialize(2048, secureRandom); - expectLastCall().anyTimes(); - expect(rsaKeyPairGenerator.genKeyPair()).andReturn(keyPair).anyTimes(); - replay(crypto, rsaKeyPairGenerator, secureRandom); - binder.bind(Crypto.class).toInstance(crypto); - binder.bind(SecureRandom.class).toInstance(secureRandom); - } catch (NoSuchAlgorithmException e) { - propagate(e); - } catch (InvalidKeySpecException e) { - propagate(e); - } catch (IOException e) { - propagate(e); - } + Crypto crypto = createMock(Crypto.class); + KeyPairGenerator rsaKeyPairGenerator = createMock(KeyPairGenerator.class); + SecureRandom secureRandom = createMock(SecureRandom.class); + expect(crypto.rsaKeyPairGenerator()).andReturn(rsaKeyPairGenerator).anyTimes(); + rsaKeyPairGenerator.initialize(2048, secureRandom); + expectLastCall().anyTimes(); + expect(rsaKeyPairGenerator.genKeyPair()).andReturn(keyPair).anyTimes(); + replay(crypto, rsaKeyPairGenerator, secureRandom); + binder.bind(Crypto.class).toInstance(crypto); + binder.bind(SecureRandom.class).toInstance(secureRandom); + // predictable node names final AtomicInteger suffix = new AtomicInteger(); binder.bind(new TypeLiteral>() { diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java index d7c9497289..9d7c4fc94a 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java @@ -47,7 +47,7 @@ public class ParseRegionListTest extends BaseGoogleComputeEngineParseTest { "us-central1", // description Region.Status.UP, // status ImmutableList.of(// - URI.create("https://www.googleapis.com/compute/v1/zones/us-central1-a"), - URI.create("https://www.googleapis.com/compute/v1/zones/us-central1-b")), // zones + URI.create(BASE_URL + "/myproject/zones/us-central1-a"), + URI.create(BASE_URL + "/myproject/zones/us-central1-b")), // zones ImmutableList.of( // Quota.create("INSTANCES", 0, 8), // Quota.create("CPUS", 0, 8), // diff --git a/providers/google-compute-engine/src/test/resources/region_get.json b/providers/google-compute-engine/src/test/resources/region_get.json index 069865d2a6..a058f5a926 100644 --- a/providers/google-compute-engine/src/test/resources/region_get.json +++ b/providers/google-compute-engine/src/test/resources/region_get.json @@ -7,8 +7,8 @@ "description": "us-central1", "status": "UP", "zones": [ - "https://www.googleapis.com/compute/v1/zones/us-central1-a", - "https://www.googleapis.com/compute/v1/zones/us-central1-b" + "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b" ], "quotas": [ { diff --git a/providers/google-compute-engine/src/test/resources/region_list.json b/providers/google-compute-engine/src/test/resources/region_list.json index ae0673e9d0..902d1b21cd 100644 --- a/providers/google-compute-engine/src/test/resources/region_list.json +++ b/providers/google-compute-engine/src/test/resources/region_list.json @@ -12,8 +12,8 @@ "description": "us-central1", "status": "UP", "zones": [ - "https://www.googleapis.com/compute/v1/zones/us-central1-a", - "https://www.googleapis.com/compute/v1/zones/us-central1-b" + "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b" ], "quotas": [ { @@ -72,7 +72,7 @@ "description": "us-central2", "status": "UP", "zones": [ - "https://www.googleapis.com/compute/v1/zones/us-central2-a" + "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central2-a" ], "quotas": [ {