mirror of https://github.com/apache/jclouds.git
JCLOUDS-512: Implement the ImageCache
This commit refactors the ImageCacheSupplier to act as a proper cache. It is used by the ImageExtesion and all operations on the images are propagated to the cache. A method has also been added to the TemplateBuilder to let users force a cache refresh. There have been several requests to provide a way to disable image caching in the compute abstraction, and this new method should fix that.
This commit is contained in:
parent
0f6ab3944f
commit
40f31786c5
|
@ -89,7 +89,6 @@ import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExc
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
@ -277,14 +276,4 @@ public class CloudStackComputeServiceContextModule extends
|
|||
NetworkType.ADVANCED, new AdvancedNetworkOptionsConverter(),
|
||||
NetworkType.BASIC, new BasicNetworkOptionsConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(ImageExtension.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(SecurityGroupExtension.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.jclouds.ec2.compute.config;
|
||||
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -30,8 +29,6 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.config.BaseComputeServiceContextModule;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.ec2.compute.EC2ComputeService;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.loaders.RegionAndIdToImage;
|
||||
|
@ -39,7 +36,6 @@ import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
|
|||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.suppliers.SetAndThrowAuthorizationExceptionSupplier;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
@ -78,9 +74,8 @@ public class EC2ComputeServiceContextModule extends BaseComputeServiceContextMod
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImageCache(
|
||||
AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier, Injector injector) {
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImages(final Supplier<Set<? extends Image>> imageSupplier,
|
||||
Injector injector) {
|
||||
final Supplier<LoadingCache<RegionAndName, ? extends Image>> cache = injector.getInstance(Key.get(new TypeLiteral<Supplier<LoadingCache<RegionAndName, ? extends Image>>>() {}));
|
||||
return new Supplier<Set<? extends Image>>() {
|
||||
@Override
|
||||
|
@ -135,15 +130,5 @@ public class EC2ComputeServiceContextModule extends BaseComputeServiceContextMod
|
|||
return new String[] {};
|
||||
return toArray(Splitter.on(',').split(amiOwners), String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(ImageExtension.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(SecurityGroupExtension.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,6 @@ import org.jclouds.compute.domain.Image;
|
|||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
@ -50,11 +48,11 @@ public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
|
|||
|
||||
@Inject
|
||||
protected EC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
|
||||
ImageCacheSupplier images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, GetImageStrategy getImageStrategy,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider,
|
||||
Supplier<LoadingCache<RegionAndName, ? extends Image>> imageMap) {
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider, getImageStrategy);
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider);
|
||||
this.lazyImageCache = imageMap;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
|
|||
import org.jclouds.ec2.compute.functions.ImagesToRegionAndIdMap;
|
||||
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
|
||||
import org.jclouds.ec2.domain.VirtualizationType;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
@ -69,6 +70,8 @@ import com.google.common.cache.CacheLoader;
|
|||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
/**
|
||||
* Tests compute service specifically to EC2.
|
||||
|
@ -236,8 +239,9 @@ public class EC2TemplateBuilderTest {
|
|||
m1_small().build(), m1_xlarge().build(), m2_xlarge().build(), m2_2xlarge().build(),
|
||||
m2_4xlarge().build(), g2_2xlarge().build(), HARDWARE_SUPPORTING_BOGUS));
|
||||
|
||||
return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60), sizes, Suppliers.ofInstance(location), optionsProvider,
|
||||
templateBuilderProvider, getImageStrategy, imageCache) {
|
||||
return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy)), sizes,
|
||||
Suppliers.ofInstance(location), optionsProvider, templateBuilderProvider, imageCache) {
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,16 +17,31 @@
|
|||
package org.jclouds.ec2.compute.extensions;
|
||||
|
||||
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.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.domain.TemplateBuilderSpec;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Live test for ec2 {@link ImageExtension} implementation
|
||||
|
@ -43,11 +58,42 @@ public class EC2ImageExtensionLiveTest extends BaseImageExtensionLiveTest {
|
|||
protected Properties setupProperties() {
|
||||
Properties overrides = super.setupProperties();
|
||||
String ebsSpec = checkNotNull(setIfTestSystemPropertyPresent(overrides, provider + ".ebs-template"), provider
|
||||
+ ".ebs-template");
|
||||
+ ".ebs-template");
|
||||
ebsTemplate = TemplateBuilderSpec.parse(ebsSpec);
|
||||
return overrides;
|
||||
}
|
||||
|
||||
// Getting an image from the cache is tricky in EC2, as images are filtered
|
||||
// by default by owner, and the image being created will be owned by the
|
||||
// current user. If the cache needs to refresh the list, the just added image
|
||||
// will be removed as the image list will be refreshed (potentially) without
|
||||
// taking into account the current user owner id. Instead of using the
|
||||
// TempalteBuilder, just inspect the ImageCacheSupplier directly
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Optional<Image> findImageWithNameInCache(String name) {
|
||||
ImageCacheSupplier imageCache = (ImageCacheSupplier) context.utils().injector()
|
||||
.getInstance(Key.get(new TypeLiteral<Supplier<Set<? extends Image>>>() {
|
||||
}, Memoized.class));
|
||||
|
||||
try {
|
||||
Field field = imageCache.getClass().getDeclaredField("imageCache");
|
||||
field.setAccessible(true);
|
||||
LoadingCache<String, Image> cache = (LoadingCache<String, Image>) field.get(imageCache);
|
||||
|
||||
return Optional.fromNullable(getOnlyElement(filter(cache.asMap().values(), new Predicate<Image>() {
|
||||
@Override
|
||||
public boolean apply(Image input) {
|
||||
return imageGroup.equals(input.getName());
|
||||
}
|
||||
}), null));
|
||||
} catch (NoSuchFieldException ex) {
|
||||
throw Throwables.propagate(ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw Throwables.propagate(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Template getNodeTemplate() {
|
||||
return view.getComputeService().templateBuilder().from(ebsTemplate).build();
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.jclouds.domain.Location;
|
|||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.functions.ImagesToRegionAndIdMap;
|
||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Functions;
|
||||
|
@ -54,6 +55,8 @@ import com.google.common.cache.CacheLoader;
|
|||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
@Test(groups = "unit", singleThreaded = true)
|
||||
public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
||||
|
@ -86,8 +89,10 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
ImagesToRegionAndIdMap.imagesToMap(images.get()))));
|
||||
}
|
||||
|
||||
return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60), sizes, Suppliers.ofInstance(defaultLocation),
|
||||
optionsProvider, templateBuilderProvider, getImageStrategy, Suppliers.<LoadingCache<RegionAndName, ? extends Image>>ofInstance(imageMap));
|
||||
return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy)), sizes,
|
||||
Suppliers.ofInstance(defaultLocation), optionsProvider, templateBuilderProvider,
|
||||
Suppliers.<LoadingCache<RegionAndName, ? extends Image>> ofInstance(imageMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -80,7 +80,6 @@ import org.jclouds.openstack.nova.v2_0.predicates.FindSecurityGroupWithNameAndRe
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
@ -280,14 +279,4 @@ public class NovaComputeServiceContextModule extends
|
|||
protected final Map<org.jclouds.openstack.nova.v2_0.domain.Image.Status, Image.Status> toPortableImageStatus() {
|
||||
return toPortableImageStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(ImageExtension.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(SecurityGroupExtension.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.jclouds.compute.options.RunScriptOptions;
|
|||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
|
||||
|
@ -71,8 +72,10 @@ import com.google.common.base.Suppliers;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
|
@ -112,9 +115,6 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
|||
}, InitializeRunScriptOnNodeOrPlaceInBadMap.class).build(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class));
|
||||
|
||||
install(new FactoryModuleBuilder().build(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class));
|
||||
|
||||
bind(new TypeLiteral<Supplier<Set<? extends Image>>>() {
|
||||
}).annotatedWith(Memoized.class).to(ImageCacheSupplier.class);
|
||||
}
|
||||
|
||||
protected void bindCredentialsOverriderFunction() {
|
||||
|
@ -238,35 +238,27 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
|||
|
||||
}, images);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("imageCache")
|
||||
protected final Supplier<Set<? extends Image>> supplyImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier, Injector injector) {
|
||||
if (shouldEagerlyParseImages(injector)) {
|
||||
return supplyImageCache(authException, seconds, imageSupplier);
|
||||
} else {
|
||||
return supplyNonParsingImageCache(authException, seconds, imageSupplier, injector);
|
||||
}
|
||||
@Memoized
|
||||
protected final Supplier<Set<? extends Image>> supplyImageCache(
|
||||
AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier, com.google.inject.Provider<GetImageStrategy> imageLoader, Injector injector) {
|
||||
Supplier<Set<? extends Image>> parsingImageSupplier = shouldEagerlyParseImages(injector) ? imageSupplier
|
||||
: supplyNonParsingImages(imageSupplier, injector);
|
||||
return new ImageCacheSupplier(parsingImageSupplier, seconds, authException, imageLoader);
|
||||
}
|
||||
|
||||
protected boolean shouldEagerlyParseImages(Injector injector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Supplier<Set<? extends Image>> supplyImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier) {
|
||||
return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, imageSupplier, seconds,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* For overriding; default impl is same as {@link supplyImageCache(seconds, imageSupplier)}
|
||||
* For overriding; default impl just returns the image supplier.
|
||||
*/
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier, Injector injector) {
|
||||
return supplyImageCache(authException, seconds, imageSupplier);
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImages(final Supplier<Set<? extends Image>> imageSupplier, Injector injector) {
|
||||
return imageSupplier;
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -312,21 +304,15 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
public final Optional<ImageExtension> guiceProvideImageExtension(Injector i) {
|
||||
return provideImageExtension(i);
|
||||
}
|
||||
|
||||
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.absent();
|
||||
Binding<ImageExtension> binding = i.getExistingBinding(Key.get(ImageExtension.class));
|
||||
return binding == null ? Optional.<ImageExtension> absent() : Optional.of(binding.getProvider().get());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected final Optional<SecurityGroupExtension> guiceProvideSecurityGroupExtension(Injector i) {
|
||||
return provideSecurityGroupExtension(i);
|
||||
}
|
||||
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.absent();
|
||||
Binding<SecurityGroupExtension> binding = i.getExistingBinding(Key.get(SecurityGroupExtension.class));
|
||||
return binding == null ? Optional.<SecurityGroupExtension> absent() : Optional.of(binding.getProvider().get());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ public interface TemplateBuilder {
|
|||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
@Beta
|
||||
TemplateBuilder from(TemplateBuilderSpec spec);
|
||||
|
||||
/**
|
||||
|
@ -66,7 +65,6 @@ public interface TemplateBuilder {
|
|||
* @param spec a String in the format specified by {@link TemplateBuilderSpec}
|
||||
* @since 1.5
|
||||
*/
|
||||
@Beta
|
||||
TemplateBuilder from(String spec);
|
||||
|
||||
/**
|
||||
|
@ -202,5 +200,19 @@ public interface TemplateBuilder {
|
|||
* Normal usage is to build up all options and pass them to the builder with a single call to this method.
|
||||
*/
|
||||
TemplateBuilder options(TemplateOptions options);
|
||||
|
||||
/**
|
||||
* Forces an image lookup against the provider to reload the image cache.
|
||||
* <p>
|
||||
* Use with caution. In some providers getting the list of images is an
|
||||
* expensive operation, and the use of the image cache is recommended. If
|
||||
* there is a need to minimize the amount of time the images are cached,
|
||||
* consider configuring the cache expiration time by setting the
|
||||
* {@link org.jclouds.Constants#PROPERTY_SESSION_INTERVAL} property.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
@Beta
|
||||
TemplateBuilder forceCacheReload();
|
||||
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ public class TemplateBuilderSpec {
|
|||
.put("loginUser", new LoginUserParser())
|
||||
.put("authenticateSudo", new AuthenticateSudoParser())
|
||||
.put("locationId", new LocationIdParser())
|
||||
.put("forceCacheReload", new ForceCacheReloadParser())
|
||||
.build();
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -177,6 +178,8 @@ public class TemplateBuilderSpec {
|
|||
Boolean authenticateSudo;
|
||||
@VisibleForTesting
|
||||
String locationId;
|
||||
@VisibleForTesting
|
||||
Boolean forceCacheReload;
|
||||
|
||||
/** Specification; used for toParseableString(). */
|
||||
// transient in case people using serializers don't want this to show up
|
||||
|
@ -279,6 +282,9 @@ public class TemplateBuilderSpec {
|
|||
if (locationId != null) {
|
||||
builder.locationId(locationId);
|
||||
}
|
||||
if (forceCacheReload != null && forceCacheReload) {
|
||||
builder.forceCacheReload();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -304,7 +310,8 @@ public class TemplateBuilderSpec {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(hardwareId, minCores, minRam, hypervisorMatches, imageId, imageNameMatches, osFamily,
|
||||
osVersionMatches, os64Bit, osArchMatches, osDescriptionMatches, loginUser, authenticateSudo, locationId);
|
||||
osVersionMatches, os64Bit, osArchMatches, osDescriptionMatches, loginUser, authenticateSudo, locationId,
|
||||
forceCacheReload);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -322,7 +329,7 @@ public class TemplateBuilderSpec {
|
|||
&& equal(osVersionMatches, that.osVersionMatches) && equal(os64Bit, that.os64Bit)
|
||||
&& equal(osArchMatches, that.osArchMatches) && equal(osDescriptionMatches, that.osDescriptionMatches)
|
||||
&& equal(loginUser, that.loginUser) && equal(authenticateSudo, that.authenticateSudo)
|
||||
&& equal(locationId, that.locationId);
|
||||
&& equal(locationId, that.locationId) && equal(forceCacheReload, that.forceCacheReload);
|
||||
}
|
||||
|
||||
/** Base class for parsing doubles. */
|
||||
|
@ -563,6 +570,15 @@ public class TemplateBuilderSpec {
|
|||
}
|
||||
}
|
||||
|
||||
/** Parse forceCacheReload */
|
||||
static class ForceCacheReloadParser extends BooleanParser {
|
||||
@Override
|
||||
protected void parseBoolean(TemplateBuilderSpec spec, boolean value) {
|
||||
checkArgument(spec.forceCacheReload == null, "forceCacheReload was already set to ", spec.forceCacheReload);
|
||||
spec.forceCacheReload = value;
|
||||
}
|
||||
}
|
||||
|
||||
public String getHardwareId() {
|
||||
return hardwareId;
|
||||
}
|
||||
|
@ -622,4 +638,9 @@ public class TemplateBuilderSpec {
|
|||
public String getSpecification() {
|
||||
return specification;
|
||||
}
|
||||
|
||||
public Boolean getForceCacheReload() {
|
||||
return forceCacheReload;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.jclouds.compute.domain.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Predicates.and;
|
||||
|
@ -52,8 +53,8 @@ import org.jclouds.compute.domain.Template;
|
|||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.domain.TemplateBuilderSpec;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.predicates.ImagePredicates;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
@ -84,7 +85,6 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
protected final Supplier<Location> defaultLocation;
|
||||
protected final Provider<TemplateOptions> optionsProvider;
|
||||
protected final Provider<TemplateBuilder> defaultTemplateProvider;
|
||||
protected final GetImageStrategy getImageStrategy;
|
||||
|
||||
@VisibleForTesting
|
||||
protected Location location;
|
||||
|
@ -128,19 +128,21 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
protected boolean fastest;
|
||||
@VisibleForTesting
|
||||
protected TemplateOptions options;
|
||||
@VisibleForTesting
|
||||
protected Boolean forceCacheReload;
|
||||
|
||||
@Inject
|
||||
protected TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
|
||||
ImageCacheSupplier images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
|
||||
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
|
||||
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, GetImageStrategy getImageStrategy) {
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) {
|
||||
this.locations = checkNotNull(locations, "locations");
|
||||
this.images = checkNotNull(images, "images");
|
||||
checkArgument(images instanceof ImageCacheSupplier, "an instance of the ImageCacheSupplier is needed");
|
||||
this.images = ImageCacheSupplier.class.cast(images);
|
||||
this.hardwares = checkNotNull(hardwares, "hardwares");
|
||||
this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
|
||||
this.optionsProvider = checkNotNull(optionsProvider, "optionsProvider");
|
||||
this.defaultTemplateProvider = checkNotNull(defaultTemplateProvider, "defaultTemplateProvider");
|
||||
this.getImageStrategy = checkNotNull(getImageStrategy, "getImageStrategy");
|
||||
}
|
||||
|
||||
static Predicate<Hardware> supportsImagesPredicate(final Iterable<? extends Image> images) {
|
||||
|
@ -175,26 +177,6 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
|
||||
});
|
||||
|
||||
private final Predicate<Image> idPredicate = new Predicate<Image>() {
|
||||
@Override
|
||||
public boolean apply(Image input) {
|
||||
boolean returnVal = true;
|
||||
if (imageId != null) {
|
||||
returnVal = imageId.equals(input.getId());
|
||||
// match our input params so that the later predicates pass.
|
||||
if (returnVal) {
|
||||
fromImage(input);
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "imageId(" + imageId + ")";
|
||||
}
|
||||
};
|
||||
|
||||
private final Predicate<OperatingSystem> osFamilyPredicate = new Predicate<OperatingSystem>() {
|
||||
|
||||
@Override
|
||||
|
@ -691,7 +673,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
|
||||
Image image = null;
|
||||
if (imageId != null) {
|
||||
image = findImageWithId(images);
|
||||
image = loadImageWithId(images);
|
||||
if (currentLocationWiderThan(image.getLocation()))
|
||||
this.location = image.getLocation();
|
||||
}
|
||||
|
@ -733,27 +715,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
return supportedImages;
|
||||
}
|
||||
|
||||
private Image findImageWithId(Set<? extends Image> images) {
|
||||
// Try to find the image in the cache and fallback to the GetImageStrategy
|
||||
// see https://issues.apache.org/jira/browse/JCLOUDS-570
|
||||
Optional<? extends Image> image = tryFind(images, idPredicate);
|
||||
if (image.isPresent()) {
|
||||
return image.get();
|
||||
private Image loadImageWithId(Iterable<? extends Image> images) {
|
||||
Optional<? extends Image> image = tryFind(images, ImagePredicates.idEquals(imageId));
|
||||
if (!image.isPresent()) {
|
||||
image = this.images.get(imageId); // Load the image from the cache, and refresh if missing
|
||||
if (!image.isPresent()) {
|
||||
throw throwNoSuchElementExceptionAfterLoggingImageIds(format("imageId(%s) not found", imageId), images);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Image %s not found in the image cache. Trying to get it from the provider...", imageId);
|
||||
// Note that this will generate make a call to the provider instead of using a cache, but
|
||||
// this will be executed rarely, only when an image is not present in the image list but
|
||||
// it actually exists in the provider. It shouldn't be an expensive call so using a cache just for
|
||||
// this corner case is overkill.
|
||||
Image imageFromProvider = getImageStrategy.getImage(imageId);
|
||||
if (imageFromProvider == null) {
|
||||
throwNoSuchElementExceptionAfterLoggingImageIds(format("%s not found", idPredicate), images);
|
||||
}
|
||||
// Register the just found image in the image cache, so subsequent uses of the TemplateBuilder and
|
||||
// the ComptueService find it.
|
||||
this.images.registerImage(imageFromProvider);
|
||||
return imageFromProvider;
|
||||
fromImage(image.get());
|
||||
return image.get();
|
||||
}
|
||||
|
||||
private Hardware findHardwareWithId(Set<? extends Hardware> hardwaresToSearch) {
|
||||
|
@ -856,10 +827,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
logger.trace("<< matched images(%s)", transform(matchingImages, imageToId));
|
||||
return imageChooser().apply(matchingImages);
|
||||
} catch (NoSuchElementException exception) {
|
||||
throwNoSuchElementExceptionAfterLoggingImageIds(format("no image matched params: %s", toString()),
|
||||
supportedImages);
|
||||
assert false;
|
||||
return null;
|
||||
throw throwNoSuchElementExceptionAfterLoggingImageIds(format("no image matched params: %s", toString()),
|
||||
supportedImages);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,7 +854,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
return maxes;
|
||||
}
|
||||
protected Set<? extends Image> getImages() {
|
||||
return images.get();
|
||||
return forceCacheReload != null && forceCacheReload ? images.rebuildCache() : images.get();
|
||||
}
|
||||
|
||||
private Predicate<Image> buildImagePredicate() {
|
||||
|
@ -1157,6 +1126,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
toString.add("os64Bit", os64Bit);
|
||||
toString.add("hardwareId", hardwareId);
|
||||
toString.add("hypervisor", hypervisor);
|
||||
toString.add("forceCacheReload", forceCacheReload);
|
||||
return toString;
|
||||
}
|
||||
|
||||
|
@ -1176,4 +1146,11 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
return from(TemplateBuilderSpec.parse(spec));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder forceCacheReload() {
|
||||
this.forceCacheReload = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.compute.extensions.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.ImageTemplate;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Delegates to the provider specific {@link ImageExtension} and takes care of
|
||||
* propagating the changes made to the images to the image cache.
|
||||
*/
|
||||
@Beta
|
||||
public class DelegatingImageExtension implements ImageExtension {
|
||||
|
||||
private final ImageCacheSupplier imageCache;
|
||||
private final ImageExtension delegate;
|
||||
|
||||
public DelegatingImageExtension(ImageCacheSupplier imageCache, ImageExtension delegate) {
|
||||
this.imageCache = checkNotNull(imageCache, "imageCache");
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
public ImageTemplate buildImageTemplateFromNode(String name, String id) {
|
||||
return delegate.buildImageTemplateFromNode(name, id);
|
||||
}
|
||||
|
||||
public ListenableFuture<Image> createImage(ImageTemplate template) {
|
||||
ListenableFuture<Image> future = delegate.createImage(template);
|
||||
Futures.addCallback(future, new FutureCallback<Image>() {
|
||||
@Override
|
||||
public void onSuccess(Image result) {
|
||||
imageCache.registerImage(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public boolean deleteImage(String id) {
|
||||
boolean success = delegate.deleteImage(id);
|
||||
if (success) {
|
||||
imageCache.removeImage(id);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
|
@ -66,6 +66,7 @@ import org.jclouds.compute.domain.Template;
|
|||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.compute.extensions.internal.DelegatingImageExtension;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
|
@ -80,6 +81,7 @@ import org.jclouds.compute.strategy.RebootNodeStrategy;
|
|||
import org.jclouds.compute.strategy.ResumeNodeStrategy;
|
||||
import org.jclouds.compute.strategy.RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
|
||||
import org.jclouds.compute.strategy.SuspendNodeStrategy;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
|
@ -180,8 +182,13 @@ public class BaseComputeService implements ComputeService {
|
|||
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
|
||||
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
|
||||
this.userExecutor = checkNotNull(userExecutor, "userExecutor");
|
||||
this.imageExtension = checkNotNull(imageExtension, "imageExtension");
|
||||
this.securityGroupExtension = checkNotNull(securityGroupExtension, "securityGroupExtension");
|
||||
if (imageExtension.isPresent() && images instanceof ImageCacheSupplier) {
|
||||
this.imageExtension = Optional.<ImageExtension> of(new DelegatingImageExtension(ImageCacheSupplier.class
|
||||
.cast(images), imageExtension.get()));
|
||||
} else {
|
||||
this.imageExtension = checkNotNull(imageExtension, "imageExtension");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,12 +17,8 @@
|
|||
package org.jclouds.compute.stub.config;
|
||||
|
||||
import org.jclouds.compute.config.JCloudsNativeComputeServiceAdapterContextModule;
|
||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.concurrent.SingleThreaded;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
@SingleThreaded
|
||||
public class StubComputeServiceContextModule extends JCloudsNativeComputeServiceAdapterContextModule {
|
||||
|
||||
|
@ -36,9 +32,4 @@ public class StubComputeServiceContextModule extends JCloudsNativeComputeService
|
|||
super.configure();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(SecurityGroupExtension.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,68 +17,181 @@
|
|||
package org.jclouds.compute.suppliers;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Iterables.concat;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
|
||||
import org.jclouds.rest.suppliers.ValueLoadedCallback;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* Image supplier that allows new images to be registered.
|
||||
* Memoized image supplier that allows new images to be registered at runtime.
|
||||
* <p>
|
||||
* This is a wrapper for the memoized image supplier (the actual image cache), to provide a way to register new images as
|
||||
* needed. Once a new image is created by the {@link org.jclouds.compute.extensions.ImageExtension}, or discovered by
|
||||
* other means (see https://issues.apache.org/jira/browse/JCLOUDS-570) this supplier will allow the image to be appended
|
||||
* to the cached list, so it can be properly used normally.
|
||||
* The memoized <code>Supplier<Set<? extends Image>></code> is a static data
|
||||
* structure that can't be properly modified at runtime. This class is a wrapper
|
||||
* for the image supplier to provide a way to register new images as needed.
|
||||
* Once a new image is created by the
|
||||
* {@link org.jclouds.compute.extensions.ImageExtension}, or discovered by other
|
||||
* means (see https://issues.apache.org/jira/browse/JCLOUDS-570) this supplier
|
||||
* will allow the image to be appended to the cached list.
|
||||
*/
|
||||
@Singleton
|
||||
public class ImageCacheSupplier implements Supplier<Set<? extends Image>> {
|
||||
@Beta
|
||||
public class ImageCacheSupplier implements Supplier<Set<? extends Image>>, ValueLoadedCallback<Set<? extends Image>> {
|
||||
|
||||
private final Supplier<Set<? extends Image>> imageCache;
|
||||
/**
|
||||
* The image supplier that fetches the images from the provider.
|
||||
*/
|
||||
private final Supplier<Set<? extends Image>> liveImageSupplier;
|
||||
|
||||
/**
|
||||
* The image supplier that loads the images and caches them for the duration
|
||||
* of the session. Delegates to the {@link #liveImageSupplier}.
|
||||
*/
|
||||
private final Supplier<Set<? extends Image>> memoizedImageSupplier;
|
||||
|
||||
/**
|
||||
* The actual image cache. It acts as a view over the memoized image supplier
|
||||
* and allows to add and remove images at runtime.
|
||||
*/
|
||||
private final LoadingCache<String, Image> imageCache;
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<String, Image> uncachedImages;
|
||||
|
||||
@Inject
|
||||
public ImageCacheSupplier(@Named("imageCache") Supplier<Set<? extends Image>> imageCache,
|
||||
@Named(PROPERTY_SESSION_INTERVAL) long sessionIntervalSeconds) {
|
||||
this.imageCache = checkNotNull(imageCache, "imageCache");
|
||||
// We use a cache to let the entries in the "uncached" set expire as soon as the image cache expires. We want the
|
||||
// uncached set to be regenerated when the original cache is also regenerated.
|
||||
this.uncachedImages = CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalSeconds, TimeUnit.SECONDS)
|
||||
.build();
|
||||
public ImageCacheSupplier(Supplier<Set<? extends Image>> imageSupplier, long sessionIntervalSeconds,
|
||||
AtomicReference<AuthorizationException> authException, final Provider<GetImageStrategy> imageLoader) {
|
||||
liveImageSupplier = imageSupplier;
|
||||
memoizedImageSupplier = MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
|
||||
imageSupplier, sessionIntervalSeconds, TimeUnit.SECONDS, this);
|
||||
imageCache = CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalSeconds, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<String, Image>() {
|
||||
@Override
|
||||
public Image load(String key) throws Exception {
|
||||
return imageLoader.get().getImage(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<? extends Image> get() {
|
||||
return ImmutableSet.copyOf(concat(imageCache.get(), uncachedImages.asMap().values()));
|
||||
// Call the memoized supplier. The "imageCache" is subscribed to the
|
||||
// reloads of the supplier once it expires. For this reason we ignore the
|
||||
// value returned by the supplier: every time it is reloaded, the cache
|
||||
// will be notified and re-populated with the fresh values. Any other call
|
||||
// to the supplier that returns a cached value will be ignored and the
|
||||
// values in the cache will be returned, as the cache properly handles
|
||||
// individual image additions and deletions (introduced, for example, by
|
||||
// the usage of the ImageExtension).
|
||||
memoizedImageSupplier.get();
|
||||
return ImmutableSet.copyOf(imageCache.asMap().values());
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache is subscribed to value loading events generated by the
|
||||
* {@link MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier}.
|
||||
* <p>
|
||||
* Every time the memoized supplier reloads a value, an event will be
|
||||
* populated and this method will handle it. This makes it possible to
|
||||
* refresh the cache with the last values everytime they are reloaded.
|
||||
*/
|
||||
@Override
|
||||
public void valueLoaded(Optional<Set<? extends Image>> value) {
|
||||
if (value.isPresent()) {
|
||||
reset(value.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cache to the given set of images.
|
||||
* <p>
|
||||
* This method is called when the memoized image supplier is reloaded, or
|
||||
* when the cache needs to be refreshed (for example when the TempalteBuilder
|
||||
* is invoked forcing a fresh image lookup.
|
||||
*/
|
||||
public void reset(Set<? extends Image> images) {
|
||||
imageCache.invalidateAll();
|
||||
imageCache.putAll(Maps.uniqueIndex(images, new Function<Image, String>() {
|
||||
@Override
|
||||
public String apply(Image input) {
|
||||
return input.getId();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the {@link #liveImageSupplier} to get the current images and
|
||||
* rebuilds the cache with them.
|
||||
*/
|
||||
public Set<? extends Image> rebuildCache() {
|
||||
Set<? extends Image> images = liveImageSupplier.get();
|
||||
reset(images);
|
||||
return images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image by id.
|
||||
* <p>
|
||||
* This methods returns the cached image, or performs a call to retrieve it
|
||||
* if the image is still not cached.
|
||||
*/
|
||||
public Optional<? extends Image> get(String id) {
|
||||
try {
|
||||
return Optional.fromNullable(imageCache.getUnchecked(id));
|
||||
} catch (Exception ex) {
|
||||
logger.error(ex, "Unexpected error loading image %s", id);
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new image in the image cache.
|
||||
* <p>
|
||||
* This method should be called to register new images into the image cache, when some image that is known to exist
|
||||
* in the provider is still not cached. For example, this can happen when an image is created after the image cache
|
||||
* has been populated for the first time.
|
||||
* This method should be called to register new images into the image cache
|
||||
* when some image that is known to exist in the provider is still not
|
||||
* cached. For example, this can happen when an image is created after the
|
||||
* image cache has been populated for the first time.
|
||||
* <p>
|
||||
* Note that this method does not check if the image is already cached, to avoid loading all images if the image
|
||||
* cache is still not populated.
|
||||
* Note that this method does not check if the image is already cached, to
|
||||
* avoid loading all images if the image cache is still not populated.
|
||||
*
|
||||
* @param image The image to be registered to the cache.
|
||||
*/
|
||||
public void registerImage(Image image) {
|
||||
checkNotNull(image, "image");
|
||||
uncachedImages.put(image.getId(), image);
|
||||
imageCache.put(image.getId(), image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an image from the image cache.
|
||||
* <p>
|
||||
* This method should be called to invalidate an already cached image, when
|
||||
* some image known to not exist in the provider is still cached.
|
||||
*
|
||||
* @param imageId The id of the image to invalidate.
|
||||
*/
|
||||
public void removeImage(String imageId) {
|
||||
imageCache.invalidate(checkNotNull(imageId, "imageId"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get(), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
|
@ -81,6 +82,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().hardwareId("m1.small"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -132,6 +134,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().minCores(32), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
|
@ -160,6 +163,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().minRam(10), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
|
@ -180,6 +184,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().minRam(10), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
|
@ -216,6 +221,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().hypervisorMatches("OpenVZ"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -246,6 +252,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().imageId("us-east-1/ami-fffffff"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -315,6 +322,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().imageNameMatches(".*w/ None.*"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -345,6 +353,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().osFamily(OsFamily.UBUNTU),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -374,6 +383,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().osVersionMatches(".*[Aa]utomated SSH Access.*"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -403,6 +413,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().os64Bit(true),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -432,6 +443,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().osArchMatches("x86"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -461,6 +473,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().osDescriptionMatches("^((?!MGC).)*$"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -491,6 +504,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertEquals(spec.loginUser, "ubuntu");
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(
|
||||
templateBuilders.get().options(overrideLoginUser("ubuntu")), templateBuilders
|
||||
.get().from(spec));
|
||||
|
@ -522,6 +536,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertEquals(spec.loginUser, "root:toor");
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(
|
||||
templateBuilders.get().options(
|
||||
overrideLoginCredentials(LoginCredentials.builder().user("root").password("toor").build())),
|
||||
|
@ -554,12 +569,13 @@ public class TemplateBuilderSpecTest {
|
|||
assertEquals(spec.loginUser, "root:toor");
|
||||
assertEquals(spec.authenticateSudo.booleanValue(), true);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(
|
||||
templateBuilders.get().options(
|
||||
overrideLoginCredentials(LoginCredentials.builder().user("root").password("toor")
|
||||
.authenticateSudo(true).build())), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
|
||||
public void testParse_authenticateSudoRepeated() {
|
||||
try {
|
||||
parse("loginUser=root:toor,authenticateSudo=true,authenticateSudo=false");
|
||||
|
@ -568,6 +584,36 @@ public class TemplateBuilderSpecTest {
|
|||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testParse_forceCacheReload() {
|
||||
TemplateBuilderSpec spec = parse("forceCacheReload=true");
|
||||
assertNull(spec.hardwareId);
|
||||
assertNull(spec.minCores);
|
||||
assertNull(spec.minRam);
|
||||
assertNull(spec.minDisk);
|
||||
assertNull(spec.imageId);
|
||||
assertNull(spec.imageNameMatches);
|
||||
assertNull(spec.hypervisorMatches);
|
||||
assertNull(spec.osFamily);
|
||||
assertNull(spec.osVersionMatches);
|
||||
assertNull(spec.os64Bit);
|
||||
assertNull(spec.osArchMatches);
|
||||
assertNull(spec.osDescriptionMatches);
|
||||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertEquals(spec.forceCacheReload.booleanValue(), true);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().forceCacheReload(), templateBuilders.get().from(spec));
|
||||
}
|
||||
|
||||
public void testParse_forceCacheReloadRepeated() {
|
||||
try {
|
||||
parse("forceCacheReload=true,forceCacheReload=false");
|
||||
fail("Expected exception");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testParse_locationId() {
|
||||
TemplateBuilderSpec spec = parse("locationId=stub");
|
||||
|
@ -586,6 +632,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertEquals(spec.locationId, "stub");
|
||||
assertNull(spec.forceCacheReload);
|
||||
assertTemplateBuilderEquivalence(templateBuilders.get().locationId("stub"),
|
||||
templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -616,6 +663,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
TemplateBuilder expected = templateBuilders.get().osVersionMatches("1[012].[01][04]").imageNameMatches(".*w/ None.*").osFamily(OsFamily.UBUNTU);
|
||||
assertTemplateBuilderEquivalence(expected, templateBuilders.get().from(spec));
|
||||
}
|
||||
|
@ -637,6 +685,7 @@ public class TemplateBuilderSpecTest {
|
|||
assertNull(spec.loginUser);
|
||||
assertNull(spec.authenticateSudo);
|
||||
assertNull(spec.locationId);
|
||||
assertNull(spec.forceCacheReload);
|
||||
TemplateBuilder expected = templateBuilders.get().minRam(10).osFamily(OsFamily.UBUNTU);
|
||||
assertTemplateBuilderEquivalence(expected, templateBuilders.get().from(spec));
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
|||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationBuilder;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
@ -62,6 +63,8 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "TemplateBuilderImplTest")
|
||||
public class TemplateBuilderImplTest {
|
||||
|
@ -468,8 +471,10 @@ public class TemplateBuilderImplTest {
|
|||
Supplier<Set<? extends Image>> images, Supplier<Set<? extends Hardware>> hardwares,
|
||||
Location defaultLocation, Provider<TemplateOptions> optionsProvider,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, GetImageStrategy getImageStrategy) {
|
||||
TemplateBuilderImpl template = new TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60), hardwares, Suppliers
|
||||
.ofInstance(defaultLocation), optionsProvider, templateBuilderProvider, getImageStrategy);
|
||||
TemplateBuilderImpl template = new TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy)), hardwares,
|
||||
Suppliers.ofInstance(defaultLocation),
|
||||
optionsProvider, templateBuilderProvider);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,10 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||
import static org.jclouds.compute.predicates.NodePredicates.inGroup;
|
||||
import static org.jclouds.util.Predicates2.retry;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -90,46 +92,40 @@ public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceConte
|
|||
|
||||
@Test(groups = { "integration", "live" }, singleThreaded = true)
|
||||
public void testCreateImage() throws RunNodesException, InterruptedException, ExecutionException {
|
||||
|
||||
ComputeService computeService = view.getComputeService();
|
||||
|
||||
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
|
||||
|
||||
assertTrue(imageExtension.isPresent(), "image extension was not present");
|
||||
|
||||
Template template = getNodeTemplate();
|
||||
|
||||
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup(imageGroup, 1, template));
|
||||
|
||||
checkReachable(node);
|
||||
|
||||
logger.info("Creating image from node %s, started with template: %s", node, template);
|
||||
|
||||
ImageTemplate newImageTemplate = imageExtension.get().buildImageTemplateFromNode(imageGroup,
|
||||
node.getId());
|
||||
|
||||
Image image = imageExtension.get().createImage(newImageTemplate).get();
|
||||
|
||||
logger.info("Image created: %s", image);
|
||||
|
||||
assertEquals(imageGroup, image.getName());
|
||||
|
||||
imageId = image.getId();
|
||||
|
||||
computeService.destroyNode(node.getId());
|
||||
|
||||
Optional<? extends Image> optImage = getImage();
|
||||
|
||||
assertTrue(optImage.isPresent());
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
|
||||
public void testImageIsCachedAfterBeingCreated() {
|
||||
Optional<Image> imageInCache = findImageWithNameInCache(imageGroup);
|
||||
assertTrue(imageInCache.isPresent());
|
||||
assertEquals(imageInCache.get().getId(), imageId);
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
|
||||
public void testSpawnNodeFromImage() throws RunNodesException {
|
||||
|
||||
ComputeService computeService = view.getComputeService();
|
||||
|
||||
Optional<? extends Image> optImage = getImage();
|
||||
|
||||
assertTrue(optImage.isPresent());
|
||||
|
||||
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup(imageGroup, 1, view
|
||||
|
@ -138,28 +134,30 @@ public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceConte
|
|||
.templateBuilder().imageId(optImage.get().getId()).fromImage(optImage.get()).build()));
|
||||
|
||||
checkReachable(node);
|
||||
|
||||
view.getComputeService().destroyNode(node.getId());
|
||||
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = { "testCreateImage",
|
||||
"testSpawnNodeFromImage" })
|
||||
"testSpawnNodeFromImage", "testImageIsCachedAfterBeingCreated" })
|
||||
public void testDeleteImage() {
|
||||
|
||||
ComputeService computeService = view.getComputeService();
|
||||
|
||||
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
|
||||
assertTrue(imageExtension.isPresent(), "image extension was not present");
|
||||
|
||||
Optional<? extends Image> optImage = getImage();
|
||||
|
||||
assertTrue(optImage.isPresent());
|
||||
|
||||
Image image = optImage.get();
|
||||
|
||||
assertTrue(imageExtension.get().deleteImage(image.getId()));
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testDeleteImage")
|
||||
public void testImageIsRemovedFromCacheAfterDeletion() {
|
||||
Optional<Image> imageInCache = findImageWithNameInCache(imageGroup);
|
||||
assertFalse(imageInCache.isPresent());
|
||||
assertFalse(getImage().isPresent());
|
||||
}
|
||||
|
||||
private Optional<? extends Image> getImage() {
|
||||
return Optional.fromNullable(view.getComputeService().getImage(imageId));
|
||||
|
@ -179,6 +177,15 @@ public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceConte
|
|||
}, getSpawnNodeMaxWait(), 1l, SECONDS).apply(client));
|
||||
}
|
||||
|
||||
protected Optional<Image> findImageWithNameInCache(String name) {
|
||||
try {
|
||||
Template template = view.getComputeService().templateBuilder().imageNameMatches(name).build();
|
||||
return Optional.of(template.getImage());
|
||||
} catch (NoSuchElementException ex) {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass(groups = { "integration", "live" })
|
||||
@Override
|
||||
protected void tearDownContext() {
|
||||
|
|
|
@ -16,20 +16,31 @@
|
|||
*/
|
||||
package org.jclouds.compute.suppliers;
|
||||
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
import static org.jclouds.compute.predicates.ImagePredicates.idEquals;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.ImageBuilder;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationBuilder;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link ImageCacheSupplier} class.
|
||||
|
@ -49,15 +60,25 @@ public class ImageCacheSupplierTest {
|
|||
|
||||
private Set<? extends Image> images = ImmutableSet.of(image);
|
||||
|
||||
private GetImageStrategy getImageStrategy = new GetImageStrategy() {
|
||||
@Override
|
||||
public Image getImage(String id) {
|
||||
return new ImageBuilder().id(id).providerId(id).name("imageName-" + id).description("imageDescription")
|
||||
.version("imageVersion").operatingSystem(os).status(Image.Status.AVAILABLE).location(location).build();
|
||||
}
|
||||
};
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testRegisterNullImageIsNotAllowed() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60);
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
imageCache.registerImage(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterImageIgnoresDuplicates() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60);
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
|
||||
imageCache.registerImage(image);
|
||||
|
@ -67,11 +88,63 @@ public class ImageCacheSupplierTest {
|
|||
|
||||
@Test
|
||||
public void testRegisterNewImage() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60);
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
|
||||
imageCache.registerImage(ImageBuilder.fromImage(image).id("newimage").build());
|
||||
|
||||
assertEquals(imageCache.get().size(), 2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testRemoveNullImageIsNotAllowed() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
imageCache.removeImage(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveImage() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
|
||||
imageCache.removeImage(image.getId());
|
||||
|
||||
assertEquals(imageCache.get().size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadImage() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 60,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
|
||||
Optional<? extends Image> image = imageCache.get("foo");
|
||||
|
||||
assertTrue(image.isPresent());
|
||||
assertEquals(image.get().getName(), "imageName-foo");
|
||||
assertEquals(imageCache.get().size(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSupplierExpirationReloadsTheCache() {
|
||||
ImageCacheSupplier imageCache = new ImageCacheSupplier(Suppliers.<Set<? extends Image>> ofInstance(images), 3,
|
||||
Atomics.<AuthorizationException> newReference(), Providers.of(getImageStrategy));
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
|
||||
Optional<? extends Image> image = imageCache.get("foo");
|
||||
|
||||
// Load an image into the cache
|
||||
assertTrue(image.isPresent());
|
||||
assertEquals(image.get().getName(), "imageName-foo");
|
||||
assertEquals(imageCache.get().size(), 2);
|
||||
|
||||
// Once the supplier expires, reloading it will laod the initial values
|
||||
// (it is a hardcoded supplier), so the just loaded image should be gone
|
||||
Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
|
||||
assertEquals(imageCache.get().size(), 1);
|
||||
assertFalse(any(imageCache.get(), idEquals("foo")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,16 +53,18 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
|||
*/
|
||||
public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> extends ForwardingObject implements
|
||||
Supplier<T> {
|
||||
|
||||
|
||||
static class SetAndThrowAuthorizationExceptionSupplierBackedLoader<V> extends CacheLoader<String, Optional<V>> {
|
||||
|
||||
private final Supplier<V> delegate;
|
||||
private final AtomicReference<AuthorizationException> authException;
|
||||
private final ValueLoadedCallback<V> valueLoadedCallback;
|
||||
|
||||
public SetAndThrowAuthorizationExceptionSupplierBackedLoader(Supplier<V> delegate,
|
||||
AtomicReference<AuthorizationException> authException) {
|
||||
AtomicReference<AuthorizationException> authException, ValueLoadedCallback<V> valueLoadedCallback) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
this.authException = checkNotNull(authException, "authException");
|
||||
this.valueLoadedCallback = checkNotNull(valueLoadedCallback, "valueLoadedCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,7 +72,9 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> ext
|
|||
if (authException.get() != null)
|
||||
throw authException.get();
|
||||
try {
|
||||
return Optional.fromNullable(delegate.get());
|
||||
Optional<V> value = Optional.fromNullable(delegate.get());
|
||||
valueLoadedCallback.valueLoaded(value);
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class);
|
||||
if (aex != null) {
|
||||
|
@ -85,7 +89,24 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> ext
|
|||
public String toString() {
|
||||
return Objects.toStringHelper(this).add("delegate", delegate).toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValueLoadedEvent<V> {
|
||||
private final Object eventKey;
|
||||
private final Optional<V> value;
|
||||
|
||||
public ValueLoadedEvent(Object eventKey, Optional<V> value) {
|
||||
this.eventKey = checkNotNull(eventKey, "eventKey");
|
||||
this.value = checkNotNull(value, "value");
|
||||
}
|
||||
|
||||
public Object getEventKey() {
|
||||
return eventKey;
|
||||
}
|
||||
|
||||
public Optional<V> getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private final Supplier<T> delegate;
|
||||
|
@ -96,16 +117,26 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> ext
|
|||
public static <T> MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> create(
|
||||
AtomicReference<AuthorizationException> authException, Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T>(authException, delegate, duration,
|
||||
unit);
|
||||
unit, new ValueLoadedCallback.NoOpCallback<T>());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a memoized supplier that calls the given callback each time values are loaded.
|
||||
*/
|
||||
public static <T> MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T> create(
|
||||
AtomicReference<AuthorizationException> authException, Supplier<T> delegate, long duration, TimeUnit unit,
|
||||
ValueLoadedCallback<T> valueLoadedCallback) {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<T>(authException, delegate, duration,
|
||||
unit, valueLoadedCallback);
|
||||
}
|
||||
|
||||
MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier(AtomicReference<AuthorizationException> authException,
|
||||
Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
Supplier<T> delegate, long duration, TimeUnit unit, ValueLoadedCallback<T> valueLoadedCallback) {
|
||||
this.delegate = delegate;
|
||||
this.duration = duration;
|
||||
this.unit = unit;
|
||||
this.cache = CacheBuilder.newBuilder().expireAfterWrite(duration, unit)
|
||||
.build(new SetAndThrowAuthorizationExceptionSupplierBackedLoader<T>(delegate, authException));
|
||||
.build(new SetAndThrowAuthorizationExceptionSupplierBackedLoader<T>(delegate, authException, valueLoadedCallback));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.rest.suppliers;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* Callback that gets called every time the supplier loads new values.
|
||||
*/
|
||||
@Beta
|
||||
public interface ValueLoadedCallback<V> {
|
||||
|
||||
void valueLoaded(Optional<V> value);
|
||||
|
||||
/** The default implementation does nothing */
|
||||
public static class NoOpCallback<V> implements ValueLoadedCallback<V> {
|
||||
@Override
|
||||
public void valueLoaded(Optional<V> value) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,22 +21,26 @@ import static com.google.common.util.concurrent.Atomics.newReference;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.SetAndThrowAuthorizationExceptionSupplierBackedLoader;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
|
||||
@Test(groups = "unit", testName = "MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest")
|
||||
public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest {
|
||||
@Test
|
||||
public void testLoaderNormal() {
|
||||
AtomicReference<AuthorizationException> authException = newReference();
|
||||
assertEquals(new SetAndThrowAuthorizationExceptionSupplierBackedLoader<String>(ofInstance("foo"),
|
||||
authException).load("KEY").get(), "foo");
|
||||
assertEquals(new SetAndThrowAuthorizationExceptionSupplierBackedLoader<String>(ofInstance("foo"), authException, new ValueLoadedCallback.NoOpCallback<String>()).load("KEY").get(), "foo");
|
||||
assertEquals(authException.get(), null);
|
||||
}
|
||||
|
||||
|
@ -48,7 +52,7 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest {
|
|||
public String get() {
|
||||
throw new AuthorizationException();
|
||||
}
|
||||
}, authException).load("KEY");
|
||||
}, authException, new ValueLoadedCallback.NoOpCallback<String>()).load("KEY");
|
||||
} finally {
|
||||
assertEquals(authException.get().getClass(), AuthorizationException.class);
|
||||
}
|
||||
|
@ -62,7 +66,7 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest {
|
|||
public String get() {
|
||||
throw new RuntimeException(new ExecutionException(new AuthorizationException()));
|
||||
}
|
||||
}, authException).load("KEY");
|
||||
}, authException, new ValueLoadedCallback.NoOpCallback<String>()).load("KEY");
|
||||
} finally {
|
||||
assertEquals(authException.get().getClass(), AuthorizationException.class);
|
||||
}
|
||||
|
@ -76,7 +80,7 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest {
|
|||
public String get() {
|
||||
throw new UncheckedExecutionException(new AuthorizationException());
|
||||
}
|
||||
}, authException).load("KEY");
|
||||
}, authException, new ValueLoadedCallback.NoOpCallback<String>()).load("KEY");
|
||||
} finally {
|
||||
assertEquals(authException.get().getClass(), AuthorizationException.class);
|
||||
}
|
||||
|
@ -90,9 +94,43 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplierTest {
|
|||
public String get() {
|
||||
throw new RuntimeException(new IllegalArgumentException("foo"));
|
||||
}
|
||||
}, authException).load("KEY");
|
||||
}, authException, new ValueLoadedCallback.NoOpCallback<String>()).load("KEY");
|
||||
} finally {
|
||||
assertEquals(authException.get().getClass(), RuntimeException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoaderNotifiesAfterReloading() {
|
||||
AtomicReference<AuthorizationException> authException = newReference();
|
||||
ValueLoadedEventHandler handler = new ValueLoadedEventHandler();
|
||||
|
||||
Supplier<String> supplier = MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
|
||||
Suppliers.<String> ofInstance("foo"), 3, TimeUnit.SECONDS, handler);
|
||||
|
||||
// The supplier loads the value initially and returns the cached values
|
||||
assertEquals(handler.count.get(), 0);
|
||||
supplier.get();
|
||||
assertEquals(handler.count.get(), 1);
|
||||
supplier.get();
|
||||
assertEquals(handler.count.get(), 1);
|
||||
|
||||
// Once expired, it reloads the values, notified the event, and updated the cache
|
||||
Uninterruptibles.sleepUninterruptibly(4, TimeUnit.SECONDS);
|
||||
supplier.get();
|
||||
assertEquals(handler.count.get(), 2);
|
||||
supplier.get();
|
||||
assertEquals(handler.count.get(), 2);
|
||||
supplier.get();
|
||||
assertEquals(handler.count.get(), 2);
|
||||
}
|
||||
|
||||
static class ValueLoadedEventHandler implements ValueLoadedCallback<String>{
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public void valueLoaded(Optional<String> value) {
|
||||
count.incrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ import org.jclouds.compute.domain.Hardware;
|
|||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.strategy.GetImageStrategy;
|
||||
import org.jclouds.compute.suppliers.ImageCacheSupplier;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
|
||||
|
@ -40,11 +38,11 @@ public class AWSEC2TemplateBuilderImpl extends EC2TemplateBuilderImpl {
|
|||
|
||||
@Inject
|
||||
protected AWSEC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
|
||||
ImageCacheSupplier images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, GetImageStrategy getImageStrategy,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider,
|
||||
Supplier<LoadingCache<RegionAndName, ? extends Image>> imageMap) {
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider, getImageStrategy, imageMap);
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider, imageMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,11 @@
|
|||
*/
|
||||
package org.jclouds.aws.ec2.compute.config;
|
||||
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.ec2.compute.AWSEC2TemplateBuilderImpl;
|
||||
|
@ -38,8 +35,6 @@ import org.jclouds.aws.ec2.compute.strategy.CreateKeyPairPlacementAndSecurityGro
|
|||
import org.jclouds.aws.ec2.compute.suppliers.AWSEC2HardwareSupplier;
|
||||
import org.jclouds.compute.config.BaseComputeServiceContextModule;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.ec2.compute.config.EC2BindComputeStrategiesByClass;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
|
@ -59,7 +54,6 @@ import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
|
|||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.suppliers.SetAndThrowAuthorizationExceptionSupplier;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.base.Throwables;
|
||||
|
@ -107,9 +101,8 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
|
|||
// duplicates EC2ComputeServiceContextModule; but that's easiest thing to do with guice; could extract to common util
|
||||
// TODO: have a another look at this (Adrian)
|
||||
@Override
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImageCache(
|
||||
AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final Supplier<Set<? extends Image>> imageSupplier, Injector injector) {
|
||||
protected Supplier<Set<? extends Image>> supplyNonParsingImages(final Supplier<Set<? extends Image>> imageSupplier,
|
||||
Injector injector) {
|
||||
final Supplier<LoadingCache<RegionAndName, ? extends Image>> cache = injector.getInstance(Key
|
||||
.get(new TypeLiteral<Supplier<LoadingCache<RegionAndName, ? extends Image>>>() {
|
||||
}));
|
||||
|
@ -170,14 +163,4 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
|
|||
protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) {
|
||||
return options.as(EC2TemplateOptions.class).userData("#cloud-config\nrepo_upgrade: none\n".getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(ImageExtension.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.of(i.getInstance(SecurityGroupExtension.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ import static com.google.common.collect.Iterables.transform;
|
|||
import org.jclouds.aws.ec2.AWSEC2Api;
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.ec2.compute.extensions.EC2ImageExtensionLiveTest;
|
||||
import org.jclouds.ec2.compute.functions.EC2ImageParser;
|
||||
import org.jclouds.ec2.options.DescribeImagesOptions;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
|
@ -33,7 +34,7 @@ import com.google.inject.Module;
|
|||
* Live test for aws-ec2 {@link ImageExtension} implementation
|
||||
*/
|
||||
@Test(groups = "live", singleThreaded = true, testName = "AWSEC2ImageExtensionLiveTest")
|
||||
public class AWSEC2ImageExtensionLiveTest extends BaseImageExtensionLiveTest {
|
||||
public class AWSEC2ImageExtensionLiveTest extends EC2ImageExtensionLiveTest {
|
||||
|
||||
public AWSEC2ImageExtensionLiveTest() {
|
||||
provider = "aws-ec2";
|
||||
|
|
|
@ -25,26 +25,14 @@ import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperti
|
|||
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
|
||||
import static org.jclouds.util.Predicates2.retry;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
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.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.ComputeService;
|
||||
import org.jclouds.compute.ComputeServiceAdapter;
|
||||
|
@ -53,8 +41,6 @@ import org.jclouds.compute.domain.Hardware;
|
|||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
|
@ -80,6 +66,19 @@ import org.jclouds.googlecomputeengine.domain.Operation;
|
|||
import org.jclouds.location.suppliers.ImplicitLocationSupplier;
|
||||
import org.jclouds.location.suppliers.implicit.FirstZone;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
public final class GoogleComputeEngineServiceContextModule
|
||||
extends ComputeServiceAdapterContextModule<Instance, MachineType, Image, Location> {
|
||||
|
||||
|
@ -197,15 +196,6 @@ public final class GoogleComputeEngineServiceContextModule
|
|||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
|
||||
@Override protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@Override protected Optional<SecurityGroupExtension> provideSecurityGroupExtension(Injector i) {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
private static final Map<Instance.Status, NodeMetadata.Status> toPortableNodeStatus =
|
||||
ImmutableMap.<Instance.Status, NodeMetadata.Status>builder()
|
||||
.put(Instance.Status.PROVISIONING, NodeMetadata.Status.PENDING)
|
||||
|
|
Loading…
Reference in New Issue