Repository: jclouds
Updated Branches:
  refs/heads/master 29655f314 -> b76a594e8


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.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/b76a594e
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/b76a594e
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/b76a594e

Branch: refs/heads/master
Commit: b76a594e816b0c04a8382b1876e160ae4581ae09
Parents: 29655f3
Author: Ignasi Barrera <[email protected]>
Authored: Wed May 16 09:27:24 2018 +0200
Committer: Ignasi Barrera <[email protected]>
Committed: Tue May 22 16:30:26 2018 +0200

----------------------------------------------------------------------
 .../compute/CloudStackComputeService.java       |  68 +++---
 .../jclouds/ec2/compute/EC2ComputeService.java  |  48 +++--
 .../nova/v2_0/compute/NovaComputeService.java   |  45 ++--
 .../config/BaseComputeServiceContextModule.java |   3 +
 .../internal/DelegatingImageExtension.java      |  68 +++++-
 .../compute/internal/BaseComputeService.java    |  12 +-
 .../internal/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(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/CloudStackComputeService.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 1109cbb..70227bd 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<String, Credentials> credentialStore,
-            @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
-            @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
-            GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
-            CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
-            DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
-            SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
-            @Named("DEFAULT") Provider<TemplateOptions> 
templateOptionsProvider,
-            @Named(TIMEOUT_NODE_RUNNING) 
Predicate<AtomicReference<NodeMetadata>> nodeRunning,
-            @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
-            @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
-            InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
-            RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
-            PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
-            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor, CloudStackApi client,
-            LoadingCache<ZoneAndName, SecurityGroup> securityGroupMap,
-            LoadingCache<String, SshKeyPair> keyPairCache,
-            Function<Set<? extends NodeMetadata>, Multimap<String, String>> 
orphanedGroupsByZoneId,
-            GroupNamingConvention.Factory namingConvention,
-            Supplier<LoadingCache<String, Zone>> zoneIdToZone,
-            Optional<ImageExtension> imageExtension,
-            Optional<SecurityGroupExtension> securityGroupExtension) {
+         @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
+         @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
+         GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
+         CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
+         DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
+         SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
+         @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
+         @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> 
nodeRunning,
+         @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
+         @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
+         InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
+         RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
+         PersistNodeCredentials persistNodeCredentials,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor, CloudStackApi client,
+         LoadingCache<ZoneAndName, SecurityGroup> securityGroupMap, 
LoadingCache<String, SshKeyPair> keyPairCache,
+         Function<Set<? extends NodeMetadata>, Multimap<String, String>> 
orphanedGroupsByZoneId,
+         GroupNamingConvention.Factory namingConvention, 
Supplier<LoadingCache<String, Zone>> zoneIdToZone,
+         Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> 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");

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
----------------------------------------------------------------------
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 37d7553..fea023c 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<String, 
Credentials> credentialStore,
-            @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
-            @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
-            GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
-            CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
-            DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
-            SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
-            @Named("DEFAULT") Provider<TemplateOptions> 
templateOptionsProvider,
-            @Named(TIMEOUT_NODE_RUNNING) 
Predicate<AtomicReference<NodeMetadata>> nodeRunning,
-            @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
-            @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
-            InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
-            RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
-            PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
-            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor, EC2Api client,
-            ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
-            @Named("SECURITY") LoadingCache<RegionAndName, String> 
securityGroupMap,
-            Optional<ImageExtension> imageExtension, 
GroupNamingConvention.Factory namingConvention,
-            @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean 
generateInstanceNames,
-            Optional<SecurityGroupExtension> securityGroupExtension) {
+         @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
+         @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
+         GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
+         CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
+         DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
+         SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
+         @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
+         @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> 
nodeRunning,
+         @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
+         @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
+         InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
+         RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
+         PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor, EC2Api client,
+         ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
+         @Named("SECURITY") LoadingCache<RegionAndName, String> 
securityGroupMap,
+         Optional<ImageExtension> imageExtension, 
GroupNamingConvention.Factory namingConvention,
+         @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean 
generateInstanceNames,
+         Optional<SecurityGroupExtension> 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;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
----------------------------------------------------------------------
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 584c95e..c28319c 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<String, 
Credentials> credentialStore,
-            @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
-            @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
-            GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
-            CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
-            DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
-            SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
-            @Named("DEFAULT") Provider<TemplateOptions> 
templateOptionsProvider,
-            @Named(TIMEOUT_NODE_RUNNING) 
Predicate<AtomicReference<NodeMetadata>> nodeRunning,
-            @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
-            @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
-            InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
-            RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
-            PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
-            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
-            CleanupResources cleanupResources,
-            Optional<ImageExtension> imageExtension,
-            Optional<SecurityGroupExtension> securityGroupExtension) {
+         @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> sizes,
+         @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
+         GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
+         CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
+         DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
startNodeStrategy,
+         SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
+         @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
+         @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> 
nodeRunning,
+         @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
+         @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
+         InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory,
+         RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess 
initAdminAccess,
+         PersistNodeCredentials persistNodeCredentials,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
+         CleanupResources cleanupResources, Optional<ImageExtension> 
imageExtension,
+         Optional<SecurityGroupExtension> 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");
 
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
----------------------------------------------------------------------
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 8d9aa0e..39265b9 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() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/compute/src/main/java/org/jclouds/compute/extensions/internal/DelegatingImageExtension.java
----------------------------------------------------------------------
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 e0ecf8b..7fd7544 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<String, Credentials> 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<String, Credentials> 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<Image> createImage(ImageTemplate template) {
+   public ListenableFuture<Image> createImage(final ImageTemplate template) {
       ListenableFuture<Image> future = delegate.createImage(template);
+
+      // Populate the default image credentials, if missing
+      future = Futures.transform(future, new Function<Image, Image>() {
+         @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<Image>() {
          @Override
          public void onSuccess(Image result) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
----------------------------------------------------------------------
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 b60592b..c8c4c1f 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<AtomicReference<NodeMetadata>> nodeTerminated;
    private final Predicate<AtomicReference<NodeMetadata>> 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<AtomicReference<NodeMetadata>> nodeSuspended,
             InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, InitAdminAccess initAdminAccess,
             RunScriptOnNode.Factory runScriptOnNodeFactory, 
PersistNodeCredentials persistNodeCredentials,
-            Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor,
-            Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> securityGroupExtension) {
+            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
+            Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> 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.<ImageExtension> of(new 
DelegatingImageExtension(ImageCacheSupplier.class
-               .cast(images), imageExtension.get()));
+         this.imageExtension = Optional.<ImageExtension> 
of(delegatingImageExtension.create(
+               ImageCacheSupplier.class.cast(images), imageExtension.get()));
       } else {
          this.imageExtension = checkNotNull(imageExtension, "imageExtension");
       }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/compute/src/test/java/org/jclouds/compute/extensions/internal/DelegatingImageExtensionTest.java
----------------------------------------------------------------------
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 0000000..4eb6a39
--- /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.<Image> 
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.<Image> 
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> 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<String, Credentials> 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> 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<String, Credentials> 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> image = new DelegatingImageExtension(imageCache, delegate, 
credsToImage, credentialStore)
+            .createImage(template);
+
+      assertEquals(image.get().getDefaultCredentials(), credentials);
+
+      verify(delegate, credsToImage);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
----------------------------------------------------------------------
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 ce8c51f..cc2f13a 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<PlacementGroup> placementGroupDeleted, 
Optional<ImageExtension> imageExtension,
          GroupNamingConvention.Factory namingConvention,
          @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean 
generateInstanceNames,
-         Optional<SecurityGroupExtension> securityGroupExtension) {
+         Optional<SecurityGroupExtension> 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;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java
----------------------------------------------------------------------
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 e676460..9a85abe 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<AtomicReference<NodeMetadata>> 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> 
imageExtension,
-         Optional<SecurityGroupExtension> securityGroupExtension) {
+         Optional<SecurityGroupExtension> 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;
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
----------------------------------------------------------------------
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 3ace4a7..96ac4d7 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<String, 
Credentials> credentialStore,
-            @Memoized Supplier<Set<? extends Image>> images,
-            @Memoized Supplier<Set<? extends Hardware>> hardwareProfiles,
-            @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
-            GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
-            CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
-            DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
resumeNodeStrategy,
-            SuspendNodeStrategy suspendNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
-            @Named("DEFAULT") Provider<TemplateOptions> 
templateOptionsProvider,
-            @Named(TIMEOUT_NODE_RUNNING) 
Predicate<AtomicReference<NodeMetadata>> nodeRunning,
-            @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
-            @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
-            InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, InitAdminAccess initAdminAccess,
-            RunScriptOnNode.Factory runScriptOnNodeFactory, 
PersistNodeCredentials persistNodeCredentials,
-            Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor,
-            Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> securityGroupExtension) {
+         @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> hardwareProfiles,
+         @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
+         GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
+         CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
+         DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
resumeNodeStrategy,
+         SuspendNodeStrategy suspendNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
+         @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
+         @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> 
nodeRunning,
+         @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
+         @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
+         InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, InitAdminAccess initAdminAccess,
+         RunScriptOnNode.Factory runScriptOnNodeFactory, 
PersistNodeCredentials persistNodeCredentials,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
+         Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> 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);
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b76a594e/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
----------------------------------------------------------------------
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 3a05f4f..1142b06 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<AtomicReference<Operation>> operationDone;
 
-   @Inject GoogleComputeEngineService(ComputeServiceContext context,
-                                        Map<String, Credentials> 
credentialStore,
-                                        @Memoized Supplier<Set<? extends 
Image>> images,
-                                        @Memoized Supplier<Set<? extends 
Hardware>> hardwareProfiles,
-                                        @Memoized Supplier<Set<? extends 
Location>> locations,
-                                        ListNodesStrategy listNodesStrategy,
-                                        GetImageStrategy getImageStrategy,
-                                        GetNodeMetadataStrategy 
getNodeMetadataStrategy,
-                                        CreateNodesInGroupThenAddToSet 
runNodesAndAddToSetStrategy,
-                                        RebootNodeStrategy rebootNodeStrategy,
-                                        DestroyNodeStrategy 
destroyNodeStrategy,
-                                        ResumeNodeStrategy resumeNodeStrategy,
-                                        SuspendNodeStrategy 
suspendNodeStrategy,
-                                        Provider<TemplateBuilder> 
templateBuilderProvider,
-                                        @Named("DEFAULT") 
Provider<TemplateOptions> templateOptionsProvider,
-                                        @Named(TIMEOUT_NODE_RUNNING) 
Predicate<AtomicReference<NodeMetadata>>
-                                                nodeRunning,
-                                        @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>>
-                                                nodeTerminated,
-                                        @Named(TIMEOUT_NODE_SUSPENDED)
-                                        
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
-                                        
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
-                                        InitAdminAccess initAdminAccess,
-                                        RunScriptOnNode.Factory 
runScriptOnNodeFactory,
-                                        PersistNodeCredentials 
persistNodeCredentials,
-                                        ComputeServiceConstants.Timeouts 
timeouts,
-                                        
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-                                        Optional<ImageExtension> 
imageExtension,
-                                        Optional<SecurityGroupExtension> 
securityGroupExtension,
-                                        Function<Set<? extends NodeMetadata>, 
Set<String>> findOrphanedGroups,
-                                        GroupNamingConvention.Factory 
namingConvention,
-                                        GoogleComputeEngineApi api,
-                                        Predicate<AtomicReference<Operation>> 
operationDone) {
+   @Inject
+   GoogleComputeEngineService(ComputeServiceContext context, Map<String, 
Credentials> credentialStore,
+         @Memoized Supplier<Set<? extends Image>> images, @Memoized 
Supplier<Set<? extends Hardware>> hardwareProfiles,
+         @Memoized Supplier<Set<? extends Location>> locations, 
ListNodesStrategy listNodesStrategy,
+         GetImageStrategy getImageStrategy, GetNodeMetadataStrategy 
getNodeMetadataStrategy,
+         CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, 
RebootNodeStrategy rebootNodeStrategy,
+         DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy 
resumeNodeStrategy,
+         SuspendNodeStrategy suspendNodeStrategy, Provider<TemplateBuilder> 
templateBuilderProvider,
+         @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
+         @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> 
nodeRunning,
+         @Named(TIMEOUT_NODE_TERMINATED) 
Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
+         @Named(TIMEOUT_NODE_SUSPENDED) 
Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
+         InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, InitAdminAccess initAdminAccess,
+         RunScriptOnNode.Factory runScriptOnNodeFactory, 
PersistNodeCredentials persistNodeCredentials,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
+         Optional<ImageExtension> imageExtension, 
Optional<SecurityGroupExtension> securityGroupExtension,
+         Function<Set<? extends NodeMetadata>, Set<String>> findOrphanedGroups,
+         GroupNamingConvention.Factory namingConvention, 
GoogleComputeEngineApi api,
+         Predicate<AtomicReference<Operation>> 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;

Reply via email to