From b76a594e816b0c04a8382b1876e160ae4581ae09 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 16 May 2018 09:27:24 +0200 Subject: [PATCH] JCLOUDS-1421: Add default credentials to images created by the ImageExtension By default, when listing images the ComputeServiceAdapter adds the default credentials for each image. This is not done when images are created by the image extension, and NPEs can appear in code that assumes the default credentials are there, as the field is not nullable. This change tries to populate the known node credentials for images created form nodes, and falls back to the default strategy to add the default credentials to an image if there are not known credentials. --- .../compute/CloudStackComputeService.java | 68 +++--- .../ec2/compute/EC2ComputeService.java | 48 ++-- .../nova/v2_0/compute/NovaComputeService.java | 45 ++-- .../BaseComputeServiceContextModule.java | 3 + .../internal/DelegatingImageExtension.java | 68 +++++- .../compute/internal/BaseComputeService.java | 12 +- .../DelegatingImageExtensionTest.java | 214 ++++++++++++++++++ .../aws/ec2/compute/AWSEC2ComputeService.java | 6 +- .../arm/compute/AzureComputeService.java | 17 +- .../gogrid/compute/GoGridComputeService.java | 40 ++-- .../compute/GoogleComputeEngineService.java | 62 ++--- 11 files changed, 423 insertions(+), 160 deletions(-) create mode 100644 compute/src/test/java/org/jclouds/compute/extensions/internal/DelegatingImageExtensionTest.java diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/CloudStackComputeService.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/CloudStackComputeService.java index 1109cbb8ab..70227bd468 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/CloudStackComputeService.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/CloudStackComputeService.java @@ -17,11 +17,11 @@ package org.jclouds.cloudstack.compute; import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.cloudstack.predicates.SshKeyPairPredicates.nameMatches; +import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; -import static org.jclouds.cloudstack.predicates.SshKeyPairPredicates.nameMatches; -import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups; import java.util.Map; import java.util.Set; @@ -33,6 +33,13 @@ import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.Constants; +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; +import org.jclouds.cloudstack.domain.SecurityGroup; +import org.jclouds.cloudstack.domain.SshKeyPair; +import org.jclouds.cloudstack.domain.Zone; +import org.jclouds.cloudstack.domain.ZoneAndName; +import org.jclouds.cloudstack.predicates.SecurityGroupPredicates; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.callables.RunScriptOnNode; @@ -42,11 +49,11 @@ import org.jclouds.compute.domain.NodeMetadata; 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.functions.GroupNamingConvention; import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -58,13 +65,6 @@ import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; -import org.jclouds.cloudstack.CloudStackApi; -import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; -import org.jclouds.cloudstack.domain.SecurityGroup; -import org.jclouds.cloudstack.domain.SshKeyPair; -import org.jclouds.cloudstack.domain.Zone; -import org.jclouds.cloudstack.domain.ZoneAndName; -import org.jclouds.cloudstack.predicates.SecurityGroupPredicates; import org.jclouds.scriptbuilder.functions.InitAdminAccess; import com.google.common.base.Function; @@ -88,32 +88,30 @@ public class CloudStackComputeService extends BaseComputeService { @Inject protected CloudStackComputeService(ComputeServiceContext context, Map credentialStore, - @Memoized Supplier> images, @Memoized Supplier> sizes, - @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, - SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, - PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CloudStackApi client, - LoadingCache securityGroupMap, - LoadingCache keyPairCache, - Function, Multimap> orphanedGroupsByZoneId, - GroupNamingConvention.Factory namingConvention, - Supplier> zoneIdToZone, - Optional imageExtension, - Optional securityGroupExtension) { + @Memoized Supplier> images, @Memoized Supplier> sizes, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CloudStackApi client, + LoadingCache securityGroupMap, LoadingCache keyPairCache, + Function, Multimap> orphanedGroupsByZoneId, + GroupNamingConvention.Factory namingConvention, Supplier> zoneIdToZone, + Optional imageExtension, Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, - getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, - startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, - nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); this.zoneIdToZone = checkNotNull(zoneIdToZone, "zoneIdToZone"); this.client = checkNotNull(client, "client"); this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap"); diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java index 37d7553a53..fea023c109 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java @@ -57,6 +57,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.functions.GroupNamingConvention; import org.jclouds.compute.functions.GroupNamingConvention.Factory; import org.jclouds.compute.internal.BaseComputeService; @@ -113,30 +114,31 @@ public class EC2ComputeService extends BaseComputeService { @Inject protected EC2ComputeService(ComputeServiceContext context, Map credentialStore, - @Memoized Supplier> images, @Memoized Supplier> sizes, - @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, - SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, - PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, EC2Api client, - ConcurrentMap credentialsMap, - @Named("SECURITY") LoadingCache securityGroupMap, - Optional imageExtension, GroupNamingConvention.Factory namingConvention, - @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, - Optional securityGroupExtension) { + @Memoized Supplier> images, @Memoized Supplier> sizes, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, EC2Api client, + ConcurrentMap credentialsMap, + @Named("SECURITY") LoadingCache securityGroupMap, + Optional imageExtension, GroupNamingConvention.Factory namingConvention, + @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, + Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, - getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, - startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, - nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); this.client = client; this.credentialsMap = credentialsMap; this.securityGroupMap = securityGroupMap; diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java index 584c95eaf3..c28319cb1d 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; + import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -39,10 +40,10 @@ import org.jclouds.compute.domain.NodeMetadata; 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.internal.BaseComputeService; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -69,28 +70,28 @@ public class NovaComputeService extends BaseComputeService { @Inject protected NovaComputeService(ComputeServiceContext context, Map credentialStore, - @Memoized Supplier> images, @Memoized Supplier> sizes, - @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, - SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, - PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - CleanupResources cleanupResources, - Optional imageExtension, - Optional securityGroupExtension) { + @Memoized Supplier> images, @Memoized Supplier> sizes, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CleanupResources cleanupResources, Optional imageExtension, + Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, - getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, - startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, - nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); this.cleanupResources = checkNotNull(cleanupResources, "cleanupResources"); } diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java index 8d9aa0ee32..39265b9ff9 100644 --- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java @@ -45,6 +45,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.functions.CreateSshClientOncePortIsListeningOnNode; import org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials; import org.jclouds.compute.options.RunScriptOptions; @@ -112,6 +113,8 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { }, InitializeRunScriptOnNodeOrPlaceInBadMap.class).build(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class)); install(new FactoryModuleBuilder().build(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class)); + + install(new FactoryModuleBuilder().build(DelegatingImageExtension.Factory.class)); } protected void bindCredentialsOverriderFunction() { diff --git a/compute/src/main/java/org/jclouds/compute/extensions/internal/DelegatingImageExtension.java b/compute/src/main/java/org/jclouds/compute/extensions/internal/DelegatingImageExtension.java index e0ecf8b79a..7fd7544ac7 100644 --- a/compute/src/main/java/org/jclouds/compute/extensions/internal/DelegatingImageExtension.java +++ b/compute/src/main/java/org/jclouds/compute/extensions/internal/DelegatingImageExtension.java @@ -16,17 +16,30 @@ */ package org.jclouds.compute.extensions.internal; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Map; +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.config.ComputeServiceAdapterContextModule.AddDefaultCredentialsToImage; +import org.jclouds.compute.domain.CloneImageTemplate; import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; import org.jclouds.compute.domain.ImageTemplate; import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.suppliers.ImageCacheSupplier; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.logging.Logger; import com.google.common.annotations.Beta; +import com.google.common.base.Function; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.inject.assistedinject.Assisted; /** * Delegates to the provider specific {@link ImageExtension} and takes care of @@ -35,20 +48,65 @@ import com.google.common.util.concurrent.ListenableFuture; @Beta public class DelegatingImageExtension implements ImageExtension { + public interface Factory { + DelegatingImageExtension create(ImageCacheSupplier imageCache, ImageExtension delegate); + } + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + private final ImageCacheSupplier imageCache; private final ImageExtension delegate; + private final AddDefaultCredentialsToImage addDefaultCredentialsToImage; + private final Map credentialStore; - public DelegatingImageExtension(ImageCacheSupplier imageCache, ImageExtension delegate) { - this.imageCache = checkNotNull(imageCache, "imageCache"); - this.delegate = checkNotNull(delegate, "delegate"); + @Inject + DelegatingImageExtension(@Assisted ImageCacheSupplier imageCache, @Assisted ImageExtension delegate, + AddDefaultCredentialsToImage addDefaultCredentialsToImage, Map credentialStore) { + this.imageCache = imageCache; + this.delegate = delegate; + this.addDefaultCredentialsToImage = addDefaultCredentialsToImage; + this.credentialStore = credentialStore; } public ImageTemplate buildImageTemplateFromNode(String name, String id) { return delegate.buildImageTemplateFromNode(name, id); } - public ListenableFuture createImage(ImageTemplate template) { + public ListenableFuture createImage(final ImageTemplate template) { ListenableFuture future = delegate.createImage(template); + + // Populate the default image credentials, if missing + future = Futures.transform(future, new Function() { + @Override + public Image apply(Image input) { + if (input.getDefaultCredentials() != null) { + return input; + } + + // If the image has been created by cloning a node, then try to + // populate the known node credentials as the default image + // credentials + if (template instanceof CloneImageTemplate) { + final CloneImageTemplate cloneImageTemplate = (CloneImageTemplate) template; + + Credentials nodeCredentials = credentialStore.get("node#" + cloneImageTemplate.getSourceNodeId()); + if (nodeCredentials != null) { + logger.info(">> Adding node(%s) credentials to image(%s)...", cloneImageTemplate.getSourceNodeId(), + cloneImageTemplate.getName()); + return ImageBuilder.fromImage(input) + .defaultCredentials(LoginCredentials.fromCredentials(nodeCredentials)).build(); + } + } + + // If no credentials are known for the node, populate the default + // credentials using the defined strategy + logger.info(">> Adding default image credentials to image(%s)...", template.getName()); + return addDefaultCredentialsToImage.apply(input); + } + }); + Futures.addCallback(future, new FutureCallback() { @Override public void onSuccess(Image result) { diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java index b60592b3f8..c8c4c1f704 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -68,7 +68,6 @@ 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; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -131,7 +130,6 @@ public class BaseComputeService implements ComputeService { private final Predicate> nodeTerminated; private final Predicate> nodeSuspended; private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; - private final Timeouts timeouts; private final InitAdminAccess initAdminAccess; private final PersistNodeCredentials persistNodeCredentials; private final RunScriptOnNode.Factory runScriptOnNodeFactory; @@ -154,8 +152,9 @@ public class BaseComputeService implements ComputeService { @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, - Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - Optional imageExtension, Optional securityGroupExtension) { + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + Optional imageExtension, Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { this.context = checkNotNull(context, "context"); this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.images = checkNotNull(images, "images"); @@ -175,15 +174,14 @@ public class BaseComputeService implements ComputeService { this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated"); this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended"); this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory"); - this.timeouts = checkNotNull(timeouts, "timeouts"); this.initAdminAccess = checkNotNull(initAdminAccess, "initAdminAccess"); this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials"); this.userExecutor = checkNotNull(userExecutor, "userExecutor"); this.securityGroupExtension = checkNotNull(securityGroupExtension, "securityGroupExtension"); if (imageExtension.isPresent() && images instanceof ImageCacheSupplier) { - this.imageExtension = Optional. of(new DelegatingImageExtension(ImageCacheSupplier.class - .cast(images), imageExtension.get())); + this.imageExtension = Optional. of(delegatingImageExtension.create( + ImageCacheSupplier.class.cast(images), imageExtension.get())); } else { this.imageExtension = checkNotNull(imageExtension, "imageExtension"); } diff --git a/compute/src/test/java/org/jclouds/compute/extensions/internal/DelegatingImageExtensionTest.java b/compute/src/test/java/org/jclouds/compute/extensions/internal/DelegatingImageExtensionTest.java new file mode 100644 index 0000000000..4eb6a39240 --- /dev/null +++ b/compute/src/test/java/org/jclouds/compute/extensions/internal/DelegatingImageExtensionTest.java @@ -0,0 +1,214 @@ +/* + * 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.util.concurrent.Futures.immediateFuture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.jclouds.compute.config.ComputeServiceAdapterContextModule.AddDefaultCredentialsToImage; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.Image.Status; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.ImageTemplate; +import org.jclouds.compute.domain.ImageTemplateBuilder.CloneImageTemplateBuilder; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.internal.ImageTemplateImpl; +import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.suppliers.ImageCacheSupplier; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.LoginCredentials; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.Futures; + +@Test(groups = "unit", testName = "DelegatingImageExtensionTest") +public class DelegatingImageExtensionTest { + + @Test + public void createImageRegistersInCacheAndAddsCredentials() { + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + + ImageTemplate template = new ImageTemplateImpl("test") { + }; + Image result = new ImageBuilder().id("test") + .operatingSystem(OperatingSystem.builder().description("test").build()).status(Status.AVAILABLE).build(); + + LoginCredentials credentials = LoginCredentials.builder().user("jclouds").password("pass").build(); + Image withCredentials = ImageBuilder.fromImage(result).defaultCredentials(credentials).build(); + + expect(delegate.createImage(template)).andReturn(immediateFuture(result)); + expect(credsToImage.apply(result)).andReturn(withCredentials); + imageCache.registerImage(withCredentials); + expectLastCall(); + replay(delegate, imageCache, credsToImage); + + new DelegatingImageExtension(imageCache, delegate, credsToImage, null).createImage(template); + + verify(delegate, imageCache, credsToImage); + } + + @Test + public void createImageDoesNotRegisterInCacheWhenFailed() { + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + + ImageTemplate template = new ImageTemplateImpl("test") { + }; + + expect(delegate.createImage(template)).andReturn(Futures. immediateFailedFuture(new RuntimeException())); + replay(delegate, imageCache, credsToImage); + + new DelegatingImageExtension(imageCache, delegate, credsToImage, null).createImage(template); + + verify(delegate, imageCache, credsToImage); + } + + @Test + public void createImageDoesNotRegisterInCacheWhenCancelled() { + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + + ImageTemplate template = new ImageTemplateImpl("test") { + }; + + expect(delegate.createImage(template)).andReturn(Futures. immediateCancelledFuture()); + replay(delegate, imageCache, credsToImage); + + new DelegatingImageExtension(imageCache, delegate, credsToImage, null).createImage(template); + + verify(delegate, imageCache, credsToImage); + } + + @Test + public void deleteUnregistersImageFromCache() { + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + + expect(delegate.deleteImage("test")).andReturn(true); + imageCache.removeImage("test"); + expectLastCall(); + replay(delegate, imageCache); + + new DelegatingImageExtension(imageCache, delegate, null, null).deleteImage("test"); + + verify(delegate, imageCache); + } + + @Test + public void deleteDoesNotUnregisterImageFromCacheWhenFailed() { + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + + expect(delegate.deleteImage("test")).andReturn(false); + replay(delegate, imageCache); + + new DelegatingImageExtension(imageCache, delegate, null, null).deleteImage("test"); + + verify(delegate, imageCache); + } + + @Test + public void createByCloningDoesNothingIfImageHasCredentials() throws InterruptedException, ExecutionException { + LoginCredentials credentials = LoginCredentials.builder().user("jclouds").password("pass").build(); + + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + + ImageTemplate template = new CloneImageTemplateBuilder().name("test").nodeId("node1").build(); + Image result = new ImageBuilder().id("test") + .operatingSystem(OperatingSystem.builder().description("test").build()).status(Status.AVAILABLE) + .defaultCredentials(credentials).build(); + + expect(delegate.createImage(template)).andReturn(immediateFuture(result)); + replay(delegate, credsToImage); + + Future image = new DelegatingImageExtension(imageCache, delegate, credsToImage, null) + .createImage(template); + + // Verify that the exact same instance is returned unmodified + assertTrue(image.get() == result); + + verify(delegate, credsToImage); + } + + @Test + public void createByCloningAddsNodeCredentials() throws InterruptedException, ExecutionException { + Credentials credentials = LoginCredentials.builder().user("jclouds").password("pass").build(); + + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + Map credentialStore = ImmutableMap.of("node#node1", credentials); + + ImageTemplate template = new CloneImageTemplateBuilder().name("test").nodeId("node1").build(); + Image result = new ImageBuilder().id("test") + .operatingSystem(OperatingSystem.builder().description("test").build()).status(Status.AVAILABLE).build(); + + expect(delegate.createImage(template)).andReturn(immediateFuture(result)); + replay(delegate, credsToImage); + + Future image = new DelegatingImageExtension(imageCache, delegate, credsToImage, credentialStore) + .createImage(template); + + assertEquals(image.get().getDefaultCredentials(), credentials); + + verify(delegate, credsToImage); + } + + @Test + public void createByCloningAddsDefaultImageCredentials() throws InterruptedException, ExecutionException { + LoginCredentials credentials = LoginCredentials.builder().user("jclouds").password("pass").build(); + + ImageCacheSupplier imageCache = createMock(ImageCacheSupplier.class); + ImageExtension delegate = createMock(ImageExtension.class); + AddDefaultCredentialsToImage credsToImage = createMock(AddDefaultCredentialsToImage.class); + Map credentialStore = Collections.emptyMap(); + + ImageTemplate template = new CloneImageTemplateBuilder().name("test").nodeId("node1").build(); + Image result = new ImageBuilder().id("test") + .operatingSystem(OperatingSystem.builder().description("test").build()).status(Status.AVAILABLE).build(); + + expect(delegate.createImage(template)).andReturn(immediateFuture(result)); + expect(credsToImage.apply(result)).andReturn( + ImageBuilder.fromImage(result).defaultCredentials(credentials).build()); + replay(delegate, credsToImage); + + Future image = new DelegatingImageExtension(imageCache, delegate, credsToImage, credentialStore) + .createImage(template); + + assertEquals(image.get().getDefaultCredentials(), credentials); + + verify(delegate, credsToImage); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java index ce8c51f039..cc2f13abc8 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java @@ -47,6 +47,7 @@ import org.jclouds.compute.domain.NodeMetadata; 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.functions.GroupNamingConvention; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; @@ -103,13 +104,14 @@ public class AWSEC2ComputeService extends EC2ComputeService { @Named("DELETED") Predicate placementGroupDeleted, Optional imageExtension, GroupNamingConvention.Factory namingConvention, @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, - Optional securityGroupExtension) { + Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials, timeouts, userExecutor, client, credentialsMap, securityGroupMap, imageExtension, - namingConvention, generateInstanceNames, securityGroupExtension); + namingConvention, generateInstanceNames, securityGroupExtension, delegatingImageExtension); this.client = client; this.placementGroupMap = placementGroupMap; this.placementGroupDeleted = placementGroupDeleted; diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index e676460f23..9a85abe940 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -16,6 +16,10 @@ */ package org.jclouds.azurecompute.arm.compute; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; + import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -38,10 +42,10 @@ import org.jclouds.compute.domain.NodeMetadata; 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.internal.BaseComputeService; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -62,10 +66,6 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; - @Singleton public class AzureComputeService extends BaseComputeService { private final CleanupResources cleanupResources; @@ -84,15 +84,16 @@ public class AzureComputeService extends BaseComputeService { @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, - PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, + PersistNodeCredentials persistNodeCredentials, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CleanupResources cleanupResources, Optional imageExtension, - Optional securityGroupExtension) { + Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); this.cleanupResources = cleanupResources; } diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java index 3ace4a75d5..96ac4d7d42 100644 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java @@ -38,10 +38,10 @@ import org.jclouds.compute.domain.NodeMetadata; 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.internal.BaseComputeService; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -65,26 +65,26 @@ import com.google.common.util.concurrent.ListeningExecutorService; public class GoGridComputeService extends BaseComputeService { @Inject protected GoGridComputeService(ComputeServiceContext context, Map credentialStore, - @Memoized Supplier> images, - @Memoized Supplier> hardwareProfiles, - @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, - SuspendNodeStrategy suspendNodeStrategy, Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, - RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, - Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - Optional imageExtension, Optional securityGroupExtension) { + @Memoized Supplier> images, @Memoized Supplier> hardwareProfiles, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, + SuspendNodeStrategy suspendNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, + RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + Optional imageExtension, Optional securityGroupExtension, + DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getImageStrategy, - getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, - resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, - nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); } /** diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java index 3a05f4f14b..1142b06a3c 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java @@ -39,11 +39,11 @@ import org.jclouds.compute.domain.NodeMetadata; 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.functions.GroupNamingConvention; import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.internal.PersistNodeCredentials; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetImageStrategy; @@ -76,44 +76,30 @@ public final class GoogleComputeEngineService extends BaseComputeService { private final GoogleComputeEngineApi api; private final Predicate> operationDone; - @Inject GoogleComputeEngineService(ComputeServiceContext context, - Map credentialStore, - @Memoized Supplier> images, - @Memoized Supplier> hardwareProfiles, - @Memoized Supplier> locations, - ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, - GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, - RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, - ResumeNodeStrategy resumeNodeStrategy, - SuspendNodeStrategy suspendNodeStrategy, - Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> - nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> - nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) - Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - InitAdminAccess initAdminAccess, - RunScriptOnNode.Factory runScriptOnNodeFactory, - PersistNodeCredentials persistNodeCredentials, - ComputeServiceConstants.Timeouts timeouts, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - Optional imageExtension, - Optional securityGroupExtension, - Function, Set> findOrphanedGroups, - GroupNamingConvention.Factory namingConvention, - GoogleComputeEngineApi api, - Predicate> operationDone) { + @Inject + GoogleComputeEngineService(ComputeServiceContext context, Map credentialStore, + @Memoized Supplier> images, @Memoized Supplier> hardwareProfiles, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, + SuspendNodeStrategy suspendNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, + RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + Optional imageExtension, Optional securityGroupExtension, + Function, Set> findOrphanedGroups, + GroupNamingConvention.Factory namingConvention, GoogleComputeEngineApi api, + Predicate> operationDone, DelegatingImageExtension.Factory delegatingImageExtension) { super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getImageStrategy, - getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, - resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, - nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, - persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, userExecutor, imageExtension, securityGroupExtension, delegatingImageExtension); this.findOrphanedGroups = findOrphanedGroups; this.namingConvention = namingConvention; this.api = api;