provisionr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From as...@apache.org
Subject [08/21] PROVISIONR-20. Change groupId from com.axemblr.provisionr to org.apache.provisionr
Date Mon, 01 Apr 2013 08:52:31 GMT
http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCache.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCache.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCache.java
deleted file mode 100644
index d4a5576..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCache.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.core;
-
-import com.amazonaws.services.ec2.AmazonEC2;
-import com.axemblr.provisionr.api.provider.Provider;
-import com.google.common.cache.LoadingCache;
-
-/**
- * Marker interface only used to hide generic type arguments
- * from Apache Aries and make Blueprint DI work as expected
- */
-public interface ProviderClientCache extends LoadingCache<Provider, AmazonEC2> {
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCacheSupplier.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCacheSupplier.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCacheSupplier.java
deleted file mode 100644
index f1ee76e..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/ProviderClientCacheSupplier.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.core;
-
-import com.amazonaws.ClientConfiguration;
-import com.amazonaws.auth.AWSCredentials;
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.services.ec2.AmazonEC2;
-import com.amazonaws.services.ec2.AmazonEC2Client;
-import com.amazonaws.services.ec2.model.DescribeRegionsRequest;
-import com.amazonaws.services.ec2.model.DescribeRegionsResult;
-import com.axemblr.provisionr.amazon.options.ProviderOptions;
-import com.axemblr.provisionr.api.provider.Provider;
-import com.google.common.base.Optional;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.base.Supplier;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.ForwardingLoadingCache;
-import com.google.common.cache.LoadingCache;
-import com.google.common.cache.RemovalListener;
-import com.google.common.cache.RemovalNotification;
-import java.util.concurrent.TimeUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ProviderClientCacheSupplier implements Supplier<ProviderClientCache> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ProviderClientCacheSupplier.class);
-
-    public static final String AXEMBLR_USER_AGENT = "Axemblr Provisionr aws-sdk-java/1.3.14";
-
-    public static final int MAX_CACHE_SIZE = 100;
-    public static final int EXPIRE_AFTER_WRITE_IN_HOURS = 2;
-
-    private static class ProviderClientCacheLoader extends CacheLoader<Provider, AmazonEC2> {
-
-        @Override
-        public AmazonEC2 load(Provider provider) throws Exception {
-            String region = Optional.fromNullable(provider.getOptions().get(ProviderOptions.REGION))
-                .or(ProviderOptions.DEFAULT_REGION);
-
-            AWSCredentials credentials = new BasicAWSCredentials(provider.getAccessKey(), provider.getSecretKey());
-            AmazonEC2 client = new AmazonEC2Client(credentials, new ClientConfiguration()
-                .withUserAgent(AXEMBLR_USER_AGENT));
-
-            if (provider.getEndpoint().isPresent()) {
-                LOG.info("Using endpoint {} as configured", provider.getEndpoint().get());
-                client.setEndpoint(provider.getEndpoint().get());
-
-            } else {
-                LOG.info(">> Searching endpoint for region {}", region);
-                DescribeRegionsRequest request = new DescribeRegionsRequest().withRegionNames(region);
-
-                DescribeRegionsResult result = client.describeRegions(request);
-                checkArgument(result.getRegions().size() == 1, "Invalid region name %s. Expected one result found %s",
-                    region, result.getRegions());
-
-                LOG.info("<< Using endpoint {} for region {}", result.getRegions().get(0).getEndpoint(), region);
-                client.setEndpoint(result.getRegions().get(0).getEndpoint());
-            }
-
-            return client;
-
-        }
-    }
-
-    public static class WrapLoadingCacheAsProviderClientCache extends ForwardingLoadingCache<Provider, AmazonEC2>
-        implements ProviderClientCache {
-
-        private final LoadingCache<Provider, AmazonEC2> delegate;
-
-        public WrapLoadingCacheAsProviderClientCache(LoadingCache<Provider, AmazonEC2> delegate) {
-            this.delegate = checkNotNull(delegate, "delegate is null");
-        }
-
-        @Override
-        protected LoadingCache<Provider, AmazonEC2> delegate() {
-            return delegate;
-        }
-    }
-
-    @Override
-    public ProviderClientCache get() {
-        final LoadingCache<Provider, AmazonEC2> cache = CacheBuilder.newBuilder()
-            .maximumSize(MAX_CACHE_SIZE)
-            .expireAfterWrite(EXPIRE_AFTER_WRITE_IN_HOURS, TimeUnit.HOURS)
-            .removalListener(new RemovalListener<Provider, AmazonEC2>() {
-                @Override
-                public void onRemoval(RemovalNotification<Provider, AmazonEC2> notification) {
-                    LOG.info("Closing client for provider: {}", notification.getKey());
-                    notification.getValue().shutdown();
-                }
-            })
-            .build(new ProviderClientCacheLoader());
-
-        return new WrapLoadingCacheAsProviderClientCache(cache);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/SecurityGroups.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/SecurityGroups.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/SecurityGroups.java
deleted file mode 100644
index 7d63ae5..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/core/SecurityGroups.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.core;
-
-public class SecurityGroups {
-
-    private SecurityGroups() {
-        /* singleton */
-    }
-
-    public static String formatNameFromBusinessKey(String businessKey) {
-        return String.format("network-%s", businessKey);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertIpPermissionToRule.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertIpPermissionToRule.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertIpPermissionToRule.java
deleted file mode 100644
index d5d004b..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertIpPermissionToRule.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.functions;
-
-import com.amazonaws.services.ec2.model.IpPermission;
-import com.axemblr.provisionr.api.network.Protocol;
-import com.axemblr.provisionr.api.network.Rule;
-import com.axemblr.provisionr.api.network.RuleBuilder;
-import com.google.common.base.Function;
-import static com.google.common.collect.Iterables.getOnlyElement;
-
-public enum ConvertIpPermissionToRule implements Function<IpPermission, Rule> {
-    FUNCTION;
-
-    @Override
-    public Rule apply(IpPermission ipPermission) {
-        final RuleBuilder builder = Rule.builder().cidr(getOnlyElement(ipPermission.getIpRanges()))
-            .protocol(Protocol.valueOf(ipPermission.getIpProtocol().toUpperCase()));
-
-        if (!ipPermission.getIpProtocol().equalsIgnoreCase("icmp")) {
-            builder.ports(ipPermission.getFromPort(), ipPermission.getToPort());
-        }
-
-        return builder.createRule();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertRuleToIpPermission.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertRuleToIpPermission.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertRuleToIpPermission.java
deleted file mode 100644
index f9fe3c7..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/functions/ConvertRuleToIpPermission.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.functions;
-
-import com.amazonaws.services.ec2.model.IpPermission;
-import com.axemblr.provisionr.api.network.Rule;
-import com.google.common.base.Function;
-
-public enum ConvertRuleToIpPermission implements Function<Rule, IpPermission> {
-    FUNCTION;
-
-    @Override
-    public IpPermission apply(Rule rule) {
-        IpPermission permission = new IpPermission()
-            .withIpProtocol(rule.getProtocol().toString().toLowerCase())
-            .withIpRanges(rule.getCidr());
-
-        if (!rule.getPorts().isEmpty()) {
-            permission.withFromPort(rule.getPorts().lowerEndpoint())
-                .withToPort(rule.getPorts().upperEndpoint());
-        } else {
-            permission.withFromPort(-1).withToPort(-1);
-        }
-        return permission;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/ProviderOptions.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/ProviderOptions.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/ProviderOptions.java
deleted file mode 100644
index 613a8f9..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/ProviderOptions.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.options;
-
-import com.google.common.base.Optional;
-
-public class ProviderOptions {
-
-    private ProviderOptions() {
-        /* singleton */
-    }
-
-    public static final String REGION = "region";
-    public static final String DEFAULT_REGION = "us-east-1";
-    public static final String SPOT_BID = "spotBid";
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/SoftwareOptions.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/SoftwareOptions.java b/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/SoftwareOptions.java
deleted file mode 100644
index f8a94ed..0000000
--- a/providers/amazon/src/main/java/com/axemblr/provisionr/amazon/options/SoftwareOptions.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
- *
- * Licensed 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 com.axemblr.provisionr.amazon.options;
-
-public class SoftwareOptions {
-
-    private SoftwareOptions() {
-        /* singleton */
-    }
-
-    public static final String DEFAULT_BASE_OPERATING_SYSTEM = "ubuntu";
-
-    public static final String BASE_OPERATING_SYSTEM_VERSION = "version";
-    public static final String DEFAULT_BASE_OPERATING_SYSTEM_VERSION = "12.04 LTS";
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/AmazonProvisionr.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/AmazonProvisionr.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/AmazonProvisionr.java
new file mode 100644
index 0000000..9f52330
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/AmazonProvisionr.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon;
+
+import com.google.common.base.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import org.activiti.engine.ProcessEngine;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.apache.provisionr.amazon.config.DefaultProviderConfig;
+import org.apache.provisionr.amazon.options.ProviderOptions;
+import org.apache.provisionr.api.pool.Machine;
+import org.apache.provisionr.api.pool.Pool;
+import org.apache.provisionr.api.provider.Provider;
+import org.apache.provisionr.core.CoreConstants;
+import org.apache.provisionr.core.CoreProcessVariables;
+import org.apache.provisionr.core.CoreSignals;
+import org.apache.provisionr.core.PoolStatus;
+import org.apache.provisionr.core.ProvisionrSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AmazonProvisionr extends ProvisionrSupport {
+
+    public static final Logger LOG = LoggerFactory.getLogger(AmazonProvisionr.class);
+
+    public static final String ID = "amazon";
+    public static final String MANAGEMENT_PROCESS_KEY = "amazonPoolManagement";
+
+    private final ProcessEngine processEngine;
+    private final Optional<Provider> defaultProvider;
+
+    public AmazonProvisionr(ProcessEngine processEngine, DefaultProviderConfig defaultProviderConfig) {
+        this.processEngine = checkNotNull(processEngine, "processEngine is null");
+        this.defaultProvider = defaultProviderConfig.createProvider();
+
+        if (defaultProvider.isPresent()) {
+            LOG.info("Default provider for AmazonProvisionr is {}", defaultProvider.get());
+        } else {
+            LOG.info("No default provider configured for AmazonProvisionr");
+        }
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public Optional<Provider> getDefaultProvider() {
+        return defaultProvider;
+    }
+
+    @Override
+    public String startPoolManagementProcess(String businessKey, Pool pool) {
+        Map<String, Object> arguments = Maps.newHashMap();
+
+        arguments.put(CoreProcessVariables.POOL, pool);
+        arguments.put(CoreProcessVariables.PROVIDER, getId());
+        arguments.put(CoreProcessVariables.POOL_BUSINESS_KEY, businessKey);
+        arguments.put(CoreProcessVariables.BOOTSTRAP_TIMEOUT,
+            convertTimeoutToISO8601TimeDuration(pool.getBootstrapTimeInSeconds()));
+        arguments.put(CoreProcessVariables.IS_CACHED_IMAGE, pool.getSoftware().isCachedImage());
+
+        /* needed because the Activiti EL doesn't work as expected and properties can't be read from the pool. */
+        arguments.put(ProcessVariables.SPOT_BID, pool.getProvider().getOption(ProviderOptions.SPOT_BID));
+
+        /* Authenticate as kermit to make the process visible in the Explorer UI */
+        processEngine.getIdentityService().setAuthenticatedUserId(CoreConstants.ACTIVITI_EXPLORER_DEFAULT_USER);
+
+        ProcessInstance instance = processEngine.getRuntimeService()
+            .startProcessInstanceByKey(MANAGEMENT_PROCESS_KEY, businessKey, arguments);
+
+        return instance.getProcessInstanceId();
+    }
+
+    @Override
+    public List<Machine> getMachines(String businessKey) {
+        ProcessInstance instance = processEngine.getRuntimeService().createProcessInstanceQuery()
+            .processInstanceBusinessKey(businessKey).singleResult();
+        if (instance == null) {
+            throw new NoSuchElementException("No active pool found with key: " + businessKey);
+        }
+
+        @SuppressWarnings("unchecked") List<Machine> machines = (List<Machine>) processEngine.getRuntimeService()
+            .getVariable(instance.getId(), CoreProcessVariables.MACHINES);
+
+        return Optional.fromNullable(machines).or(Collections.<Machine>emptyList());
+    }
+
+    @Override
+    public String getStatus(String businessKey) {
+        ProcessInstance instance = processEngine.getRuntimeService().createProcessInstanceQuery()
+            .processInstanceBusinessKey(businessKey).singleResult();
+        if (instance == null) {
+            throw new NoSuchElementException("No active pool found with key: " + businessKey);
+        }
+
+        String status = (String) processEngine.getRuntimeService().getVariable(instance.getId(),
+            CoreProcessVariables.STATUS);
+
+        return Optional.fromNullable(status).or(PoolStatus.UNDEFINED);
+    }
+
+    @Override
+    public void destroyPool(String businessKey) {
+        triggerSignalEvent(processEngine, businessKey, CoreSignals.TERMINATE_POOL);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/ProcessVariables.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/ProcessVariables.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/ProcessVariables.java
new file mode 100644
index 0000000..53ae9e5
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/ProcessVariables.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon;
+
+public class ProcessVariables {
+
+    private ProcessVariables() {
+        /* singleton */
+    }
+
+    /**
+     * ID of a base image from which to create the others in the pool
+     */
+    public static final String IMAGE_ID = "imageId";
+
+    /**
+     * The reservation ID for a pool as String
+     *
+     * @see org.apache.provisionr.amazon.activities.RunOnDemandInstances
+     */
+    public static final String RESERVATION_ID = "reservationId";
+
+    /**
+     * The amount the user is willing to pay for spot instances in the
+     * Amazon pool he's trying to start. If set, the request is for spot
+     * instances, if null the request is for on demand instances.
+     * 
+     * @see org.apache.provisionr.amazon.activities.RunSpotInstances
+     */
+    public static final String SPOT_BID = "spotBid";
+
+    /**
+     * Flag that gets set when the process attempts to send spot requests
+     * for the first time. Because the describe call is not consistent
+     * until a reasonable delay passes, this will be used to timeout the
+     * Activiti retries so that the requests are not resent if they were
+     * successful. 
+     * 
+     * @see org.apache.provisionr.amazon.activities.RunSpotInstances
+     */
+    public static final String SPOT_REQUESTS_SENT = "spotRequestsSent";
+
+    /**
+     * List of request IDs as returned by Amazon for spot instances. These need to 
+     * be followed up to get the actual instance IDs.
+     * 
+     * @see org.apache.provisionr.amazon.activities.RunSpotInstances
+     */
+    public static final String SPOT_INSTANCE_REQUEST_IDS = "spotInstanceRequestIds";
+
+    /**
+     * Have all spot instance requests been handled by Amazon? (none are pending)
+     * 
+     *  @see org.apache.provisionr.amazon.activities.CheckNoRequestsAreOpen
+     */
+    public static final String NO_SPOT_INSTANCE_REQUESTS_OPEN = "noSpotInstanceRequestsOpen";
+
+    /**
+     * Are all spot instance requests in an active state? (none cancelled, none terminated)
+     * 
+     * @see org.apache.provisionr.amazon.activities.CheckAllRequestsAreActive
+     */
+    public static final String ALL_SPOT_INSTANCE_REQUESTS_ACTIVE = "allSpotInstanceRequestsActive";
+
+    /**
+     * List of instance IDs as returned by Amazon
+     *
+     * @see org.apache.provisionr.amazon.activities.RunOnDemandInstances
+     */
+    public static final String INSTANCE_IDS = "instanceIds";
+
+    /**
+     * List of requested EBS volume IDs
+     * 
+     * @see org.apache.provisionr.amazon.activities.CreateEBSVolumes
+     */
+    public static final String VOLUME_IDS = "volumeIds"; 
+
+    /**
+     * Are all started instances running?
+     *
+     * @see org.apache.provisionr.amazon.activities.CheckAllInstancesAreRunning
+     */
+    public static final String ALL_INSTANCES_RUNNING = "allInstancesRunning";
+
+    /**
+     * Are all instances marked as terminated?
+     *
+     * @see org.apache.provisionr.amazon.activities.CheckAllInstancesAreTerminated
+     */
+    public static final String ALL_INSTANCES_TERMINATED = "allInstancesTerminated";
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllInstancesMatchPredicate.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllInstancesMatchPredicate.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllInstancesMatchPredicate.java
new file mode 100644
index 0000000..57363a8
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllInstancesMatchPredicate.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
+import com.amazonaws.services.ec2.model.DescribeInstancesResult;
+import com.amazonaws.services.ec2.model.Instance;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+import java.util.List;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AllInstancesMatchPredicate extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AllInstancesMatchPredicate.class);
+
+    private final String resultVariable;
+    private final Predicate<Instance> predicate;
+
+    protected AllInstancesMatchPredicate(ProviderClientCache cache,
+                                         String resultVariable, Predicate<Instance> predicate) {
+        super(cache);
+        this.resultVariable = checkNotNull(resultVariable, "resultVariable is null");
+        this.predicate = checkNotNull(predicate, "predicate is null");
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        @SuppressWarnings("unchecked")
+        Optional<List<String>> instanceIds = 
+            Optional.fromNullable((List<String>) execution.getVariable(ProcessVariables.INSTANCE_IDS));
+
+        if (!instanceIds.isPresent()) {
+            LOG.warn("<< Process variable '{}' not found", ProcessVariables.INSTANCE_IDS);
+            return;
+        } else if (instanceIds.get().size() == 0) {
+            LOG.info(">> No instances are currently registered in the process.");
+            return;
+        }
+
+        try {
+            DescribeInstancesResult result = client.describeInstances(new DescribeInstancesRequest()
+                .withInstanceIds(instanceIds.get()));
+
+            List<Instance> instances = collectInstancesFromReservations(result.getReservations());
+
+            if (Iterables.all(instances, predicate)) {
+                LOG.info(">> All {} instances match predicate {} ", instanceIds, predicate);
+                execution.setVariable(resultVariable, true);
+
+            } else {
+                LOG.info("<< Not all instances {} match predicate {}", instanceIds, predicate);
+                execution.setVariable(resultVariable, false);
+            }
+        } catch (AmazonServiceException exception) {
+            if (exception.getErrorCode().equalsIgnoreCase("InvalidInstanceID.NotFound")) {
+                LOG.warn("<< Got error InvalidInstanceID.NotFound. Assuming predicate {} is false", predicate);
+                execution.setVariable(resultVariable, false);
+            } else {
+                throw Throwables.propagate(exception);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllSpotRequestsMatchPredicate.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllSpotRequestsMatchPredicate.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllSpotRequestsMatchPredicate.java
new file mode 100644
index 0000000..b02a1bd
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AllSpotRequestsMatchPredicate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsResult;
+import com.amazonaws.services.ec2.model.SpotInstanceRequest;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+public class AllSpotRequestsMatchPredicate extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AllSpotRequestsMatchPredicate.class);
+
+    protected final String resultVariable;
+    private final Predicate<SpotInstanceRequest> predicate;
+
+    protected AllSpotRequestsMatchPredicate(ProviderClientCache cache, String resultVariable, 
+            Predicate<SpotInstanceRequest> predicate) {
+        super(cache);
+        this.resultVariable = checkNotNull(resultVariable, "resultVariable is null");
+        this.predicate = checkNotNull(predicate, "predicate is null");
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+
+        LOG.info(">> Checking if all spot requests match predicate {}", predicate);
+
+        @SuppressWarnings("unchecked")
+        List<String> requestIds = (List<String>) execution.getVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS);
+        checkNotNull(requestIds, "process variable '{}' not found", ProcessVariables.SPOT_INSTANCE_REQUEST_IDS);
+
+        DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest();
+        describeRequest.setSpotInstanceRequestIds(requestIds);
+
+        // Retrieve all of the requests we want to monitor.
+        DescribeSpotInstanceRequestsResult describeResult = client.describeSpotInstanceRequests(describeRequest);
+        List<SpotInstanceRequest> requests = describeResult.getSpotInstanceRequests();
+
+        if (Iterables.all(requests, predicate)) {
+            LOG.info(">> All {} requests match predicate {} ", requests, predicate);
+            execution.setVariable(resultVariable, true);
+        } else {
+            LOG.info("<< Not all requests {} match predicate {}", requests, predicate);
+            execution.setVariable(resultVariable, false);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AmazonActivity.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AmazonActivity.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AmazonActivity.java
new file mode 100644
index 0000000..6a743aa
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/AmazonActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.Instance;
+import com.amazonaws.services.ec2.model.Reservation;
+import com.google.common.base.Function;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.JavaDelegate;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import org.apache.provisionr.core.CoreProcessVariables;
+
+public abstract class AmazonActivity implements JavaDelegate {
+
+    private final ProviderClientCache providerClientCache;
+
+    protected AmazonActivity(ProviderClientCache providerClientCache) {
+        this.providerClientCache = checkNotNull(providerClientCache, "providerClientCache is null");
+    }
+
+    /**
+     * Amazon specific activity implementation
+     *
+     * @param client    Amazon client created using the pool provider
+     * @param pool      Virtual machines pool description
+     * @param execution Activiti execution context
+     */
+    public abstract void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception;
+
+    /**
+     * Wrap the abstract {@code execute} method with the logic that knows how to create the Amazon client
+     */
+    @Override
+    public void execute(DelegateExecution execution) throws Exception {
+        Pool pool = (Pool) execution.getVariable(CoreProcessVariables.POOL);
+        checkNotNull(pool, "Please add the pool description as a process " +
+            "variable with the name '%s'.", CoreProcessVariables.POOL);
+
+        execute(providerClientCache.getUnchecked(pool.getProvider()), pool, execution);
+    }
+
+    protected List<Instance> collectInstancesFromReservations(List<Reservation> reservation) {
+        /* Make a copy as an ArrayList to force lazy collection evaluation */
+        List<List<Instance>> allInstances = Lists.transform(reservation, new Function<Reservation, List<Instance>>() {
+            @Override
+            public List<Instance> apply(Reservation reservation) {
+                return reservation.getInstances();
+            }
+        });
+
+        return Lists.newArrayList(Iterables.concat(allInstances));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CancelSpotRequests.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CancelSpotRequests.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CancelSpotRequests.java
new file mode 100644
index 0000000..77e3709
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CancelSpotRequests.java
@@ -0,0 +1,36 @@
+package org.apache.provisionr.amazon.activities;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.CancelSpotInstanceRequestsRequest;
+import org.apache.provisionr.amazon.AmazonProvisionr;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+
+public class CancelSpotRequests extends AmazonActivity {
+
+    public static final Logger LOG = LoggerFactory.getLogger(AmazonProvisionr.class);
+
+    public CancelSpotRequests(ProviderClientCache providerClientCache) {
+        super(providerClientCache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        @SuppressWarnings("unchecked")
+        List<String> requests = (List<String>) execution.getVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS);
+        checkNotNull(requests, "process variable '{}' not found", ProcessVariables.SPOT_INSTANCE_REQUEST_IDS);
+        if (requests.size() > 0) {
+            client.cancelSpotInstanceRequests(new CancelSpotInstanceRequestsRequest()
+                    .withSpotInstanceRequestIds(requests));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreRunning.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreRunning.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreRunning.java
new file mode 100644
index 0000000..f7c5d13
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreRunning.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.model.Instance;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import com.google.common.base.Predicate;
+
+public class CheckAllInstancesAreRunning extends AllInstancesMatchPredicate {
+
+    public static class InstanceIsRunning implements Predicate<Instance> {
+        @Override
+        public boolean apply(Instance instance) {
+            return instance.getState().getName().equalsIgnoreCase("running");
+        }
+
+        @Override
+        public String toString() {
+            return "InstanceIsRunning{}";
+        }
+    }
+
+    public CheckAllInstancesAreRunning(ProviderClientCache cache) {
+        super(cache, ProcessVariables.ALL_INSTANCES_RUNNING, new InstanceIsRunning());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreTerminated.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreTerminated.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreTerminated.java
new file mode 100644
index 0000000..b2ba3da
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllInstancesAreTerminated.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.model.Instance;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import com.google.common.base.Predicate;
+
+public class CheckAllInstancesAreTerminated extends AllInstancesMatchPredicate {
+
+    public static class InstanceIsTerminated implements Predicate<Instance> {
+        @Override
+        public boolean apply(Instance instance) {
+            return instance.getState().getName().equalsIgnoreCase("terminated");
+        }
+
+        @Override
+        public String toString() {
+            return "InstanceIsTerminated{}";
+        }
+    }
+
+    public CheckAllInstancesAreTerminated(ProviderClientCache cache) {
+        super(cache, ProcessVariables.ALL_INSTANCES_TERMINATED, new InstanceIsTerminated());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllRequestsAreActive.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllRequestsAreActive.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllRequestsAreActive.java
new file mode 100644
index 0000000..1103d77
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckAllRequestsAreActive.java
@@ -0,0 +1,35 @@
+package org.apache.provisionr.amazon.activities;
+
+import org.activiti.engine.delegate.DelegateExecution;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.SpotInstanceRequest;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Predicate;
+
+public class CheckAllRequestsAreActive extends AllSpotRequestsMatchPredicate {
+
+    public static class RequestIsActive implements Predicate<SpotInstanceRequest> {
+
+        @Override
+        public boolean apply(SpotInstanceRequest request) {
+            return "active".equalsIgnoreCase(request.getState());
+        }
+
+        @Override
+        public String toString() {
+            return "RequestIsActive{}";
+        }
+    }
+
+    public CheckAllRequestsAreActive(ProviderClientCache cache) {
+        super(cache, ProcessVariables.ALL_SPOT_INSTANCE_REQUESTS_ACTIVE, new RequestIsActive());
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        super.execute(client, pool, execution);        
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckNoRequestsAreOpen.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckNoRequestsAreOpen.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckNoRequestsAreOpen.java
new file mode 100644
index 0000000..2eebaa2
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/CheckNoRequestsAreOpen.java
@@ -0,0 +1,26 @@
+package org.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.model.SpotInstanceRequest;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import com.google.common.base.Predicate;
+
+public class CheckNoRequestsAreOpen extends AllSpotRequestsMatchPredicate {
+
+    public static class RequestIsNotOpen implements Predicate<SpotInstanceRequest> {
+
+        @Override
+        public boolean apply(SpotInstanceRequest request) {
+            return !"open".equalsIgnoreCase(request.getState());
+        }
+
+        @Override
+        public String toString() {
+            return "RequestIsNotOpen{}";
+        }
+    }
+
+    public CheckNoRequestsAreOpen(ProviderClientCache cache) {
+        super(cache, ProcessVariables.NO_SPOT_INSTANCE_REQUESTS_OPEN, new RequestIsNotOpen());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteKeyPair.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteKeyPair.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteKeyPair.java
new file mode 100644
index 0000000..09bb575
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteKeyPair.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DeleteKeyPairRequest;
+import org.apache.provisionr.amazon.core.KeyPairs;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DeleteKeyPair extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DeleteKeyPair.class);
+
+    public DeleteKeyPair(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) {
+        String keyName = KeyPairs.formatNameFromBusinessKey(execution.getProcessBusinessKey());
+
+        LOG.info(">> Deleting key pair {}", keyName);
+        client.deleteKeyPair(new DeleteKeyPairRequest().withKeyName(keyName));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteSecurityGroup.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteSecurityGroup.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteSecurityGroup.java
new file mode 100644
index 0000000..427e849
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DeleteSecurityGroup.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DeleteSecurityGroupRequest;
+import org.apache.provisionr.amazon.core.ErrorCodes;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.amazon.core.SecurityGroups;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Throwables;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DeleteSecurityGroup extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DeleteSecurityGroup.class);
+
+    public DeleteSecurityGroup(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) {
+        final String groupName = SecurityGroups.formatNameFromBusinessKey(execution.getProcessBusinessKey());
+        try {
+            LOG.info(">> Deleting Security Group {}", groupName);
+
+            client.deleteSecurityGroup(new DeleteSecurityGroupRequest().withGroupName(groupName));
+
+        } catch (AmazonServiceException e) {
+            if (e.getErrorCode().equals(ErrorCodes.SECURITY_GROUP_NOT_FOUND)) {
+                LOG.info("<< Security Group {} not found. Ignoring this error.", groupName);
+            } else {
+                throw Throwables.propagate(e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DumpConsoleOutput.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DumpConsoleOutput.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DumpConsoleOutput.java
new file mode 100644
index 0000000..3519f53
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/DumpConsoleOutput.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.GetConsoleOutputRequest;
+import com.amazonaws.services.ec2.model.GetConsoleOutputResult;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Machine;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Charsets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import net.schmizz.sshj.common.Base64;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DumpConsoleOutput extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DumpConsoleOutput.class);
+
+    public DumpConsoleOutput(ProviderClientCache providerClientCache) {
+        super(providerClientCache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        Machine machine = (Machine) execution.getVariable("machine");
+        checkNotNull(machine, "expecting 'machine' as a process variable");
+
+        LOG.info(">> Requesting console output for instance {}", machine.getExternalId());
+        GetConsoleOutputResult result = client.getConsoleOutput(
+            new GetConsoleOutputRequest().withInstanceId(machine.getExternalId()));
+        if (result.getOutput() != null) {
+            String content = new String(Base64.decode(result.getOutput()), Charsets.UTF_8);
+            LOG.info("<< Console output for instance {}: {}", machine.getExternalId(), content);
+        } else {
+            LOG.warn("<< Console output was null for instance {}", machine.getExternalId());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureKeyPairExists.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureKeyPairExists.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureKeyPairExists.java
new file mode 100644
index 0000000..38098c6
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureKeyPairExists.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DeleteKeyPairRequest;
+import com.amazonaws.services.ec2.model.ImportKeyPairRequest;
+import com.amazonaws.services.ec2.model.ImportKeyPairResult;
+import org.apache.provisionr.amazon.core.ErrorCodes;
+import org.apache.provisionr.amazon.core.KeyPairs;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EnsureKeyPairExists extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EnsureKeyPairExists.class);
+
+    public EnsureKeyPairExists(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) {
+        String keyName = KeyPairs.formatNameFromBusinessKey(execution.getProcessBusinessKey());
+        LOG.info(">> Importing admin access key pair as {}", keyName);
+
+        final String publicKey = pool.getAdminAccess().getPublicKey();
+        try {
+            importPoolPublicKeyPair(client, keyName, publicKey);
+
+        } catch (AmazonServiceException e) {
+            if (e.getErrorCode().equals(ErrorCodes.DUPLICATE_KEYPAIR)) {
+                LOG.info("<< Duplicate key pair found. Re-importing from pool description");
+
+                client.deleteKeyPair(new DeleteKeyPairRequest().withKeyName(keyName));
+                importPoolPublicKeyPair(client, keyName, publicKey);
+            }
+        }
+    }
+
+    private void importPoolPublicKeyPair(AmazonEC2 client, String keyName, String publicKey) {
+        ImportKeyPairResult result = client.importKeyPair(new ImportKeyPairRequest()
+            .withKeyName(keyName).withPublicKeyMaterial(publicKey));
+        LOG.info("<< Created remote key with fingerprint {}", result.getKeyFingerprint());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureSecurityGroupExists.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureSecurityGroupExists.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureSecurityGroupExists.java
new file mode 100644
index 0000000..e46fbd7
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/EnsureSecurityGroupExists.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
+import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
+import com.amazonaws.services.ec2.model.CreateSecurityGroupResult;
+import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
+import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
+import com.amazonaws.services.ec2.model.IpPermission;
+import com.amazonaws.services.ec2.model.RevokeSecurityGroupIngressRequest;
+import org.apache.provisionr.amazon.core.ErrorCodes;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.amazon.core.SecurityGroups;
+import org.apache.provisionr.amazon.functions.ConvertRuleToIpPermission;
+import org.apache.provisionr.api.network.Network;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Sets.difference;
+import java.util.Set;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EnsureSecurityGroupExists extends AmazonActivity {
+
+    public static final Logger LOG = LoggerFactory.getLogger(EnsureSecurityGroupExists.class);
+
+    public EnsureSecurityGroupExists(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) {
+        final String businessKey = execution.getProcessBusinessKey();
+        final String groupName = SecurityGroups.formatNameFromBusinessKey(businessKey);
+
+        try {
+            LOG.info(">> Creating Security Group with name {}", groupName);
+            CreateSecurityGroupRequest request = new CreateSecurityGroupRequest()
+                .withGroupName(groupName).withDescription("Security Group for " + businessKey);
+
+            CreateSecurityGroupResult result = client.createSecurityGroup(request);
+            LOG.info("<< Created Security Group with ID {}", result.getGroupId());
+
+        } catch (AmazonServiceException e) {
+            if (e.getErrorCode().equals(ErrorCodes.DUPLICATE_SECURITY_GROUP)) {
+                LOG.warn(String.format("<< Security Group %s already exists. " +
+                    "Synchronizing ingress rules.", groupName), e);
+            } else {
+                throw Throwables.propagate(e);
+            }
+        }
+
+        synchronizeIngressRules(client, groupName, pool.getNetwork());
+    }
+
+    private void synchronizeIngressRules(AmazonEC2 client, String groupName, Network network) {
+        DescribeSecurityGroupsResult result = client.describeSecurityGroups(
+            new DescribeSecurityGroupsRequest().withGroupNames(groupName));
+
+        Set<IpPermission> existingPermissions = ImmutableSet.copyOf(getOnlyElement(
+            result.getSecurityGroups()).getIpPermissions());
+
+        Set<IpPermission> expectedPermissions = ImmutableSet.copyOf(
+            Iterables.transform(network.getIngress(), ConvertRuleToIpPermission.FUNCTION));
+
+        authorizeIngressRules(client, groupName, difference(expectedPermissions, existingPermissions));
+        revokeIngressRules(client, groupName, difference(existingPermissions, expectedPermissions));
+    }
+
+    private void authorizeIngressRules(AmazonEC2 client, String groupName, Set<IpPermission> ipPermissions) {
+        if (!ipPermissions.isEmpty()) {
+            LOG.info(">> Authorizing Security Group Ingress Rules {} for {}", ipPermissions, groupName);
+
+            AuthorizeSecurityGroupIngressRequest request = new AuthorizeSecurityGroupIngressRequest()
+                .withGroupName(groupName).withIpPermissions(ipPermissions);
+            client.authorizeSecurityGroupIngress(request);
+        }
+    }
+
+    private void revokeIngressRules(AmazonEC2 client, String groupName, Set<IpPermission> ipPermissions) {
+        if (!ipPermissions.isEmpty()) {
+            LOG.info(">> Revoking Security Group Ingress Rules: {} for {}", ipPermissions, groupName);
+
+            RevokeSecurityGroupIngressRequest request = new RevokeSecurityGroupIngressRequest()
+                .withGroupName(groupName).withIpPermissions(ipPermissions);
+            client.revokeSecurityGroupIngress(request);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/GetInstanceIdsFromSpotRequests.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/GetInstanceIdsFromSpotRequests.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/GetInstanceIdsFromSpotRequests.java
new file mode 100644
index 0000000..7fa9b1b
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/GetInstanceIdsFromSpotRequests.java
@@ -0,0 +1,44 @@
+package org.apache.provisionr.amazon.activities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsResult;
+import com.amazonaws.services.ec2.model.SpotInstanceRequest;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+
+public class GetInstanceIdsFromSpotRequests extends AmazonActivity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GetInstanceIdsFromSpotRequests.class);
+    
+    public GetInstanceIdsFromSpotRequests(ProviderClientCache providerClientCache) {
+        super(providerClientCache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        LOG.info(">> retrieving instance Ids from spot request Ids");
+
+        @SuppressWarnings("unchecked")
+        List<String> requestIds = 
+                (List<String>) execution.getVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS);
+        DescribeSpotInstanceRequestsResult result = client.describeSpotInstanceRequests(
+                new DescribeSpotInstanceRequestsRequest().withSpotInstanceRequestIds(requestIds));
+        List<String> instanceIds = new ArrayList<String>();
+        for (SpotInstanceRequest spotRequest : result.getSpotInstanceRequests()) {
+            if (spotRequest.getInstanceId() != null) {
+                instanceIds.add(spotRequest.getInstanceId());
+            }
+        }
+        execution.setVariable(ProcessVariables.INSTANCE_IDS, instanceIds);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/PublishListOfMachines.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/PublishListOfMachines.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/PublishListOfMachines.java
new file mode 100644
index 0000000..71d9bc4
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/PublishListOfMachines.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+ *
+ * Licensed 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.apache.provisionr.amazon.activities;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
+import com.amazonaws.services.ec2.model.DescribeInstancesResult;
+import com.amazonaws.services.ec2.model.Instance;
+import com.google.common.base.Function;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Machine;
+import org.apache.provisionr.api.pool.Pool;
+import org.apache.provisionr.core.CoreProcessVariables;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Use the IDs to retrieve details about the running machines and
+ * store them as a process variable (machines)
+ *
+ * @see Machine
+ */
+public class PublishListOfMachines extends AmazonActivity {
+
+    public static final Logger LOG = LoggerFactory.getLogger(PublishListOfMachines.class);
+
+    public PublishListOfMachines(ProviderClientCache providerClientCache) {
+        super(providerClientCache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        @SuppressWarnings("unchecked")
+        List<String> instanceIds = (List<String>) execution.getVariable(ProcessVariables.INSTANCE_IDS);
+        checkNotNull(instanceIds, "%s not found as a process variable", ProcessVariables.INSTANCE_IDS);
+
+        LOG.info(">> Describing instances {}", instanceIds);
+        DescribeInstancesResult result = client.describeInstances(new DescribeInstancesRequest()
+            .withInstanceIds(instanceIds));
+
+        LOG.info("<< Got the following reservations: {}", result.getReservations());
+
+        List<Instance> instances = collectInstancesFromReservations(result.getReservations());
+        List<Machine> machines = Lists.transform(instances,
+            new Function<Instance, Machine>() {
+                @Override
+                public Machine apply(Instance instance) {
+                    return Machine.builder()
+                        .externalId(instance.getInstanceId())
+                        .publicDnsName(instance.getPublicDnsName())
+                        .publicIp(instance.getPublicIpAddress())
+                        .privateDnsName(instance.getPrivateDnsName())
+                        .privateIp(instance.getPrivateIpAddress())
+                        .createMachine();
+                }
+            });
+
+        /* Create a new ArrayList to force evaluation for lazy collections */
+        execution.setVariable(CoreProcessVariables.MACHINES, Lists.newArrayList(machines));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunInstances.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunInstances.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunInstances.java
new file mode 100644
index 0000000..aa04a2d
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunInstances.java
@@ -0,0 +1,144 @@
+package org.apache.provisionr.amazon.activities;
+
+import com.amazonaws.AmazonWebServiceRequest;
+import com.amazonaws.services.ec2.model.BlockDeviceMapping;
+import com.amazonaws.services.ec2.model.EbsBlockDevice;
+import com.amazonaws.services.ec2.model.LaunchSpecification;
+import com.amazonaws.services.ec2.model.RequestSpotInstancesRequest;
+import com.amazonaws.services.ec2.model.RunInstancesRequest;
+import com.amazonaws.services.ec2.model.SpotInstanceType;
+import com.google.common.base.Charsets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Strings;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Resources;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.List;
+import net.schmizz.sshj.common.Base64;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.apache.provisionr.amazon.core.ImageTable;
+import org.apache.provisionr.amazon.core.ImageTableQuery;
+import org.apache.provisionr.amazon.core.KeyPairs;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.amazon.core.SecurityGroups;
+import org.apache.provisionr.amazon.options.ProviderOptions;
+import org.apache.provisionr.amazon.options.SoftwareOptions;
+import org.apache.provisionr.api.hardware.BlockDevice;
+import org.apache.provisionr.api.pool.Pool;
+import org.apache.provisionr.api.provider.Provider;
+
+public abstract class RunInstances extends AmazonActivity {
+
+    public static final String DEFAULT_ARCH = "amd64";
+    public static final String DEFAULT_TYPE = "instance-store";
+    public static final String DEFAULT_AMI_ID = "ami-0cdf4965"; // Ubuntu 12.10 x64
+
+    protected RunInstances(ProviderClientCache providerClientCache) {
+        super(providerClientCache);
+    }
+
+    protected RunInstancesRequest createOnDemandInstancesRequest(Pool pool, DelegateExecution execution)
+        throws IOException {
+        return (RunInstancesRequest) createRequest(pool, execution, false);
+    }
+
+    protected RequestSpotInstancesRequest createSpotInstancesRequest(Pool pool, DelegateExecution execution)
+        throws IOException {
+        return (RequestSpotInstancesRequest) createRequest(pool, execution, true);
+    }
+
+    private AmazonWebServiceRequest createRequest(Pool pool, DelegateExecution execution, boolean spot)
+        throws IOException {
+        final String businessKey = execution.getProcessBusinessKey();
+
+        final String securityGroupName = SecurityGroups.formatNameFromBusinessKey(businessKey);
+        final String keyPairName = KeyPairs.formatNameFromBusinessKey(businessKey);
+
+        final String instanceType = pool.getHardware().getType();
+        final String imageId = getImageIdFromPoolConfigurationOrQueryImageTable(
+            pool, pool.getProvider(), instanceType);
+
+        final String userData = Resources.toString(Resources.getResource(RunInstances.class,
+            "/org/apache/provisionr/amazon/userdata.sh"), Charsets.UTF_8);
+
+        List<BlockDevice> blockDevices = pool.getHardware().getBlockDevices();
+        List<BlockDeviceMapping> blockDeviceMappings = Lists.newArrayList();
+        if (blockDevices != null && blockDevices.size() > 0) {
+            for (BlockDevice device : blockDevices) {
+                blockDeviceMappings.add(new BlockDeviceMapping()
+                    .withDeviceName(device.getName())
+                    .withEbs(new EbsBlockDevice()
+                        .withVolumeSize(device.getSize())
+                        .withDeleteOnTermination(true)
+                    ));
+            }
+        }
+
+        if (spot) {
+            Calendar validUntil = Calendar.getInstance();
+            validUntil.add(Calendar.MINUTE, 10);
+            final String spotPrice = checkNotNull(pool.getProvider().getOption(ProviderOptions.SPOT_BID),
+                "The bid for spot instances was not specified");
+            LaunchSpecification ls = new LaunchSpecification()
+                .withInstanceType(instanceType)
+                .withKeyName(keyPairName)
+                .withImageId(imageId)
+                .withBlockDeviceMappings(blockDeviceMappings)
+                .withSecurityGroups(Lists.newArrayList(securityGroupName))
+                .withUserData(Base64.encodeBytes(userData.getBytes(Charsets.UTF_8)));
+            return new RequestSpotInstancesRequest()
+                .withSpotPrice(spotPrice)
+                .withLaunchSpecification(ls)
+                .withLaunchGroup(businessKey)
+                .withInstanceCount(pool.getExpectedSize())
+                .withType(SpotInstanceType.OneTime)
+                .withValidUntil(validUntil.getTime());
+        } else {
+            return new RunInstancesRequest()
+                .withClientToken(businessKey)
+                .withSecurityGroups(securityGroupName)
+                .withKeyName(keyPairName)
+                .withInstanceType(instanceType)
+                .withImageId(imageId)
+                .withBlockDeviceMappings(blockDeviceMappings)
+                .withMinCount(pool.getMinSize())
+                .withMaxCount(pool.getExpectedSize())
+                .withUserData(Base64.encodeBytes(userData.getBytes(Charsets.UTF_8)));
+        }
+    }
+
+    private String getImageIdFromPoolConfigurationOrQueryImageTable(
+        Pool pool, Provider provider, String instanceType
+    ) {
+        final String imageId = pool.getSoftware().getImageId();
+        if (!Strings.isNullOrEmpty(imageId)) {
+            return "default".equals(imageId) ? DEFAULT_AMI_ID : imageId;
+        }
+
+        ImageTable imageTable;
+        try {
+            imageTable = ImageTable.fromCsvResource("/org/apache/provisionr/amazon/ubuntu.csv");
+        } catch (IOException e) {
+            throw Throwables.propagate(e);
+        }
+
+        final String region = provider.getOptionOr(ProviderOptions.REGION, ProviderOptions.DEFAULT_REGION);
+        final String version = provider.getOptionOr(SoftwareOptions.BASE_OPERATING_SYSTEM_VERSION,
+            SoftwareOptions.DEFAULT_BASE_OPERATING_SYSTEM_VERSION);
+
+        ImageTableQuery query = imageTable.query()
+            .filterBy("region", region)
+            .filterBy("version", version)
+            .filterBy("arch", DEFAULT_ARCH);
+
+        if (instanceType.equals("t1.micro")) {
+            query.filterBy("type", "ebs");
+        } else {
+            query.filterBy("type", DEFAULT_TYPE);
+        }
+
+        return query.singleResult();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunOnDemandInstances.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunOnDemandInstances.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunOnDemandInstances.java
new file mode 100644
index 0000000..b415818
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunOnDemandInstances.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+*
+* Licensed 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.apache.provisionr.amazon.activities;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.Instance;
+import com.amazonaws.services.ec2.model.RunInstancesRequest;
+import com.amazonaws.services.ec2.model.RunInstancesResult;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+public class RunOnDemandInstances extends RunInstances {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RunOnDemandInstances.class);
+
+    public static final String DEFAULT_ARCH = "amd64";
+    public static final String DEFAULT_TYPE = "instance-store";
+
+    public RunOnDemandInstances(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws IOException {
+
+        final RunInstancesRequest request = createOnDemandInstancesRequest(pool, execution);
+        // TODO allow for more options (e.g. monitoring & termination protection etc.)
+
+        LOG.info(">> Sending RunInstances request: {}", request);
+        RunInstancesResult result = client.runInstances(request);
+        LOG.info("<< Got RunInstances result: {}", result);
+
+        // TODO tag instances: managed-by: Apache Provisionr, business-key: ID etc.
+
+        execution.setVariable(ProcessVariables.RESERVATION_ID,
+            result.getReservation().getReservationId());
+        execution.setVariable(ProcessVariables.INSTANCE_IDS,
+            collectInstanceIdsAsList(result.getReservation().getInstances()));
+    }
+
+
+    private List<String> collectInstanceIdsAsList(List<Instance> instances) {
+        /* Make a copy as an ArrayList to force lazy collection evaluation */
+        return Lists.newArrayList(Lists.transform(instances,
+            new Function<Instance, String>() {
+                @Override
+                public String apply(Instance instance) {
+                    return instance.getInstanceId();
+                }
+            }));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-provisionr/blob/6ba40c4b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunSpotInstances.java
----------------------------------------------------------------------
diff --git a/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunSpotInstances.java b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunSpotInstances.java
new file mode 100644
index 0000000..0a1d06b
--- /dev/null
+++ b/providers/amazon/src/main/java/org/apache/provisionr/amazon/activities/RunSpotInstances.java
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2012 S.C. Axemblr Software Solutions S.R.L
+*
+* Licensed 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.apache.provisionr.amazon.activities;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest;
+import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsResult;
+import com.amazonaws.services.ec2.model.Filter;
+import com.amazonaws.services.ec2.model.RequestSpotInstancesRequest;
+import com.amazonaws.services.ec2.model.RequestSpotInstancesResult;
+import com.amazonaws.services.ec2.model.SpotInstanceRequest;
+import org.apache.provisionr.amazon.ProcessVariables;
+import org.apache.provisionr.amazon.core.ProviderClientCache;
+import org.apache.provisionr.api.pool.Pool;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+
+public class RunSpotInstances extends RunInstances {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RunSpotInstances.class);
+    
+    public RunSpotInstances(ProviderClientCache cache) {
+        super(cache);
+    }
+
+    @Override
+    public void execute(AmazonEC2 client, Pool pool, DelegateExecution execution) throws Exception {
+        /* before sending a new request, we check to see if we already registered
+           a launch group with the process ID, if yes, we don't re-send the request */
+        final String businessKey = execution.getProcessBusinessKey();
+
+        /* we timeout if requests have already been sent - the activity is being retried. */
+        Optional<Object> alreadySent = Optional.fromNullable(
+                execution.getVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS));
+
+        if (alreadySent.isPresent()) {
+            DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest()
+                    .withFilters(new Filter()
+                        .withName("launch-group").withValues(businessKey)
+                        .withName("state").withValues("open", "active"));
+            Stopwatch stopwatch = new Stopwatch().start();
+            while (stopwatch.elapsedTime(TimeUnit.MINUTES) < 2) {
+                DescribeSpotInstanceRequestsResult result = client.describeSpotInstanceRequests(describeRequest);
+                List<SpotInstanceRequest> pending = result.getSpotInstanceRequests();
+                if (pending.size() > 0) {
+                    LOG.info("Not resending spot instance requests {} for businessKey: {}.", pending, businessKey);
+                    execution.setVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS, 
+                            collectSpotInstanceRequestIds(pending));
+                    return;
+                }
+                LOG.info("The describe call has not returned anything yet, waiting 20s and retrying.");
+                Uninterruptibles.sleepUninterruptibly(20, TimeUnit.SECONDS);
+            }
+        }
+
+        final RequestSpotInstancesRequest request = createSpotInstancesRequest(pool, execution);
+        execution.setVariable(ProcessVariables.SPOT_REQUESTS_SENT, true);
+        RequestSpotInstancesResult requestResult = client.requestSpotInstances(request);
+        List<String> spotInstanceRequestIds = collectSpotInstanceRequestIds(requestResult.getSpotInstanceRequests());
+
+        execution.setVariable(ProcessVariables.SPOT_INSTANCE_REQUEST_IDS, spotInstanceRequestIds);
+    }
+    
+    private List<String> collectSpotInstanceRequestIds(List<SpotInstanceRequest> requestResponses) {
+        /* Make a copy as an ArrayList to force lazy collection evaluation */
+        return Lists.newArrayList(Lists.transform(requestResponses,
+            new Function<SpotInstanceRequest, String>() {
+                @Override
+                public String apply(SpotInstanceRequest instanceRequest) {
+                    return instanceRequest.getSpotInstanceRequestId();
+                }
+            }));
+    }
+}


Mime
View raw message