http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/ImagesToRegionAndIdMap.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/ImagesToRegionAndIdMap.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/ImagesToRegionAndIdMap.java
new file mode 100644
index 0000000..1e71648
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/ImagesToRegionAndIdMap.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ec2.compute.functions;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Maps.uniqueIndex;
+
+import java.util.Map;
+
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+
+import com.google.common.base.Function;
+
+@Singleton
+public class ImagesToRegionAndIdMap implements Function<Iterable<? extends 
Image>, Map<RegionAndName, ? extends Image>> {
+
+   public static Map<RegionAndName, ? extends Image> imagesToMap(Iterable<? 
extends Image> input) {
+      return new ImagesToRegionAndIdMap().apply(input);
+   }
+
+   @Override
+   public Map<RegionAndName, ? extends Image> apply(Iterable<? extends Image> 
input) {
+      return uniqueIndex(input, new Function<Image, RegionAndName>() {
+
+         @Override
+         public RegionAndName apply(Image from) {
+            checkState(from.getLocation() != null,
+                     "in ec2, image locations cannot be null; typically, they 
are Region-scoped");
+            return new RegionAndName(from.getLocation().getId(), 
from.getProviderId());
+         }
+
+      });
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PasswordCredentialsFromWindowsInstance.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PasswordCredentialsFromWindowsInstance.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PasswordCredentialsFromWindowsInstance.java
new file mode 100644
index 0000000..93ea29e
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PasswordCredentialsFromWindowsInstance.java
@@ -0,0 +1,119 @@
+/*
+ * 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.ec2.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.util.Predicates2.retry;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.PasswordDataAndPrivateKey;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.domain.KeyPair;
+import org.jclouds.ec2.domain.PasswordData;
+import org.jclouds.ec2.domain.RunningInstance;
+import org.jclouds.ec2.features.WindowsApi;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.logging.Logger;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.util.concurrent.Atomics;
+
+@Singleton
+public class PasswordCredentialsFromWindowsInstance implements 
Function<RunningInstance, LoginCredentials> {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final ConcurrentMap<RegionAndName, KeyPair> credentialsMap;
+   private final EC2Api ec2Api;
+   private final Function<PasswordDataAndPrivateKey, LoginCredentials> 
pwDataToLoginCredentials;
+
+   @Inject
+   protected 
PasswordCredentialsFromWindowsInstance(ConcurrentMap<RegionAndName, KeyPair> 
credentialsMap,
+            EC2Api ec2Api, Function<PasswordDataAndPrivateKey, 
LoginCredentials> pwDataToLoginCredentials) {
+      this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
+      this.ec2Api = checkNotNull(ec2Api, "ec2Api");
+      this.pwDataToLoginCredentials = checkNotNull(pwDataToLoginCredentials, 
"pwDataToLoginCredentials");
+   }
+
+   @Override
+   public LoginCredentials apply(final RunningInstance instance) {
+      Optional<? extends WindowsApi> windowsOption = 
ec2Api.getWindowsApiForRegion(instance.getRegion());
+      checkState(windowsOption.isPresent(), "windows feature not present in 
region %s", instance.getRegion());
+      
+      final WindowsApi windowsApi = windowsOption.get();
+      
+      LoginCredentials credentials = 
LoginCredentials.builder().user("Administrator").noPrivateKey().build();
+      String privateKey = getPrivateKeyOrNull(instance);
+      if (privateKey == null) {
+         return credentials;
+      }
+      // The Administrator password will take some time before it is ready - 
Amazon says
+      // sometimes
+      // 15 minutes.
+      // So we create a predicate that tests if the password is ready, and 
wrap it in a retryable
+      // predicate.
+      final AtomicReference<PasswordData> data = Atomics.newReference();
+      Predicate<String> passwordReady = new Predicate<String>() {
+         @Override
+         public boolean apply(@Nullable String s) {
+            if (Strings.isNullOrEmpty(s))
+               return false;
+            data.set(windowsApi.getPasswordDataForInstance(instance.getId()));
+            if (data.get() == null)
+               return false;
+            return !Strings.isNullOrEmpty(data.get().getPasswordData());
+         }
+      };
+
+      // TODO: parameterize
+      Predicate<String> passwordReadyRetryable = retry(passwordReady, 600, 10, 
SECONDS);
+
+      logger.debug(">> awaiting password data for instance(%s/%s)", 
instance.getRegion(), instance.getId());
+      if (passwordReadyRetryable.apply(instance.getId())) {
+         credentials = pwDataToLoginCredentials.apply(new 
PasswordDataAndPrivateKey(data.get(), privateKey));
+         logger.debug("<< obtained password data for instance(%s/%s)", 
instance.getRegion(), instance.getId());
+      } else {
+         logger.debug("<< unable to get password data for instance(%s/%s)", 
instance.getRegion(), instance.getId());
+      }
+      return credentials;
+   }
+
+   @VisibleForTesting
+   String getPrivateKeyOrNull(RunningInstance instance) {
+      KeyPair keyPair = credentialsMap.get(new 
RegionAndName(instance.getRegion(), instance.getKeyName()));
+      return keyPair != null ? keyPair.getKeyMaterial() : null;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PresentInstances.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PresentInstances.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PresentInstances.java
new file mode 100644
index 0000000..b341007
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/PresentInstances.java
@@ -0,0 +1,82 @@
+/*
+ * 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.ec2.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.toArray;
+import static com.google.common.collect.Multimaps.index;
+import static com.google.common.collect.Multimaps.transformValues;
+import static org.jclouds.ec2.compute.domain.RegionAndName.nameFunction;
+import static org.jclouds.ec2.compute.domain.RegionAndName.regionFunction;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.domain.RunningInstance;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Multimap;
+import com.google.inject.Inject;
+
+/**
+ * returns the instances present in the list.  Makes a single rest call per 
aggregate on region.
+ */
+@Singleton
+public class PresentInstances implements Function<Set<RegionAndName>, 
Set<RunningInstance>> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final EC2Api client;
+
+   @Inject
+   public PresentInstances(EC2Api client) {
+      this.client = checkNotNull(client, "client");
+   }
+
+   @Override
+   public Set<RunningInstance> apply(Set<RegionAndName> regionAndIds) {
+      if (checkNotNull(regionAndIds, "regionAndIds").isEmpty())
+         return ImmutableSet.of();
+      Builder<RunningInstance> builder = ImmutableSet.<RunningInstance> 
builder();
+      Multimap<String, String> regionToInstanceIds = 
transformValues(index(regionAndIds, regionFunction()),
+            nameFunction());
+      for (Map.Entry<String, Collection<String>> entry : 
regionToInstanceIds.asMap().entrySet()) {
+         String region = entry.getKey();
+         Collection<String> instanceIds = entry.getValue();
+         logger.trace("looking for instances %s in region %s", instanceIds, 
region);
+         
builder.addAll(concat(client.getInstanceApi().get().describeInstancesInRegion(region,
+               toArray(instanceIds, String.class))));
+      }
+      return builder.build();
+   }
+   
+   @Override
+   public String toString() {
+      return "presentInstances()";
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
new file mode 100644
index 0000000..e0f5e95
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
@@ -0,0 +1,254 @@
+/*
+ * 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.ec2.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Strings.emptyToNull;
+import static com.google.common.collect.Iterables.filter;
+import static 
org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.internal.VolumeImpl;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.domain.BlockDevice;
+import org.jclouds.ec2.domain.InstanceState;
+import org.jclouds.ec2.domain.RootDeviceType;
+import org.jclouds.ec2.domain.RunningInstance;
+import org.jclouds.logging.Logger;
+import org.jclouds.util.InetAddresses2.IsPrivateIPAddress;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.inject.Inject;
+
+@Singleton
+public class RunningInstanceToNodeMetadata implements 
Function<RunningInstance, NodeMetadata> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   protected final Supplier<Set<? extends Location>> locations;
+   protected final Supplier<Set<? extends Hardware>> hardware;
+   protected final Supplier<LoadingCache<RegionAndName, ? extends Image>> 
imageMap;
+   protected final Map<String, Credentials> credentialStore;
+   protected final Map<InstanceState, Status> instanceToNodeStatus;
+   protected final GroupNamingConvention.Factory namingConvention;
+
+   @Inject
+   protected RunningInstanceToNodeMetadata(Map<InstanceState, Status> 
instanceToNodeStatus,
+            Map<String, Credentials> credentialStore, 
Supplier<LoadingCache<RegionAndName, ? extends Image>> imageMap,
+            @Memoized Supplier<Set<? extends Location>> locations, @Memoized 
Supplier<Set<? extends Hardware>> hardware,
+            GroupNamingConvention.Factory namingConvention) {
+      this.locations = checkNotNull(locations, "locations");
+      this.hardware = checkNotNull(hardware, "hardware");
+      this.imageMap = checkNotNull(imageMap, "imageMap");
+      this.instanceToNodeStatus = checkNotNull(instanceToNodeStatus, 
"instanceToNodeStatus");
+      this.credentialStore = checkNotNull(credentialStore, "credentialStore");
+      this.namingConvention = checkNotNull(namingConvention, 
"namingConvention");
+   }
+
+   @Override
+   public NodeMetadata apply(RunningInstance instance) {
+      if (instance == null || instance.getId() == null)
+         return null;
+      NodeMetadataBuilder builder = new NodeMetadataBuilder();
+      builder.name(instance.getTags().get("Name"));
+      addMetadataAndParseTagsFromValuesOfEmptyString(builder, 
instance.getTags());
+      builder.providerId(instance.getId());
+      builder.id(instance.getRegion() + "/" + instance.getId());
+      String group = getGroupForInstance(instance);
+      builder.group(group);
+      // standard convention from aws-ec2, which might not be re-used outside.
+      if (instance.getPrivateDnsName() != null)
+         builder.hostname(instance.getPrivateDnsName().replaceAll("\\..*", 
""));
+      addCredentialsForInstance(builder, instance);
+      builder.status(instanceToNodeStatus.get(instance.getInstanceState()));
+      builder.backendStatus(instance.getRawState());
+
+      // collect all ip addresses into one bundle in case the api mistakenly 
put a private address
+      // into the public address field
+      Builder<String> addressesBuilder = ImmutableSet.builder();
+      if (emptyToNull(instance.getIpAddress()) != null)
+         addressesBuilder.add(instance.getIpAddress());
+      if (emptyToNull(instance.getPrivateIpAddress()) != null)
+         addressesBuilder.add(instance.getPrivateIpAddress());
+
+      Set<String> addresses = addressesBuilder.build();
+
+      builder.publicAddresses(filter(addresses, 
not(IsPrivateIPAddress.INSTANCE)));
+      builder.privateAddresses(filter(addresses, IsPrivateIPAddress.INSTANCE));
+      builder.hardware(parseHardware(instance));
+      Location location = getLocationForAvailabilityZoneOrRegion(instance);
+      builder.location(location);
+      builder.imageId(instance.getRegion() + "/" + instance.getImageId());
+
+      // extract the operating system from the image
+      RegionAndName regionAndName = new RegionAndName(instance.getRegion(), 
instance.getImageId());
+      try {
+         Image image = imageMap.get().getUnchecked(regionAndName);
+         if (image != null)
+            builder.operatingSystem(image.getOperatingSystem());
+      } catch (CacheLoader.InvalidCacheLoadException e) {
+         logger.debug("image not found for %s: %s", regionAndName, e);
+      } catch (UncheckedExecutionException e) {
+         logger.debug("error getting image for %s: %s", regionAndName, e);
+      }
+      return builder.build();
+   }
+
+   protected void addCredentialsForInstance(NodeMetadataBuilder builder, 
RunningInstance instance) {
+      
builder.credentials(LoginCredentials.fromCredentials(credentialStore.get("node#"
 + instance.getRegion() + "/"
+            + instance.getId())));
+   }
+
+   protected Hardware parseHardware(final RunningInstance instance) {
+      Hardware hardware = getHardwareForInstance(instance);
+
+      if (hardware != null) {
+         hardware = 
HardwareBuilder.fromHardware(hardware).volumes(addEBS(instance, 
hardware.getVolumes())).build();
+      }
+      return hardware;
+   }
+
+   @VisibleForTesting
+   static List<Volume> addEBS(final RunningInstance instance, Iterable<? 
extends Volume> volumes) {
+      Iterable<Volume> ebsVolumes = 
Iterables.transform(instance.getEbsBlockDevices().entrySet(),
+               new Function<Entry<String, BlockDevice>, Volume>() {
+
+                  @Override
+                  public Volume apply(Entry<String, BlockDevice> from) {
+                     return new VolumeImpl(from.getValue().getVolumeId(), 
Volume.Type.SAN, null, from.getKey(),
+                              instance.getRootDeviceName() != null
+                                       && 
instance.getRootDeviceName().equals(from.getKey()), true);
+                  }
+               });
+
+      if (instance.getRootDeviceType() == RootDeviceType.EBS) {
+         volumes = Iterables.filter(volumes, new Predicate<Volume>() {
+
+            @Override
+            public boolean apply(Volume input) {
+               return !input.isBootDevice();
+            }
+
+         });
+
+      }
+      return Lists.newArrayList(Iterables.concat(volumes, ebsVolumes));
+
+   }
+
+   @VisibleForTesting
+   String getGroupForInstance(final RunningInstance instance) {
+      String group = parseGroupFrom(instance, instance.getGroupNames());
+      if (group == null && instance.getKeyName() != null) {
+         // when not using a generated security group, e.g. in VPC, try from 
key:
+         group = parseGroupFrom(instance, 
Sets.newHashSet(instance.getKeyName()));
+      }
+      return group;
+   }
+
+   private String parseGroupFrom(final RunningInstance instance, final 
Set<String> data) {
+      String group = null;
+      try {
+         Predicate<String> containsAnyGroup = 
namingConvention.create().containsAnyGroup();
+         String encodedGroup = Iterables.getOnlyElement(Iterables.filter(data, 
containsAnyGroup));
+         group = namingConvention.create().extractGroup(encodedGroup);
+      } catch (NoSuchElementException e) {
+         logger.debug("no group parsed from %s's data: %s", instance.getId(), 
data);
+      } catch (IllegalArgumentException e) {
+         logger.debug("too many groups match naming convention; %s's data: 
%s", instance.getId(), data);
+      }
+      return group;
+   }
+
+   @VisibleForTesting
+   Hardware getHardwareForInstance(final RunningInstance instance) {
+      try {
+         return Iterables.find(hardware.get(), new Predicate<Hardware>() {
+
+            @Override
+            public boolean apply(Hardware input) {
+               return input.getId().equals(instance.getInstanceType());
+            }
+
+         });
+      } catch (NoSuchElementException e) {
+         logger.debug("couldn't match instance type %s in: %s", 
instance.getInstanceType(), hardware.get());
+         return null;
+      }
+   }
+
+   private Location getLocationForAvailabilityZoneOrRegion(final 
RunningInstance instance) {
+      Location location = findLocationWithId(instance.getAvailabilityZone());
+      if (location == null)
+         location = findLocationWithId(instance.getRegion());
+      return location;
+   }
+
+   private Location findLocationWithId(final String locationId) {
+      if (locationId == null)
+         return null;
+      try {
+         Location location = Iterables.find(locations.get(), new 
Predicate<Location>() {
+
+            @Override
+            public boolean apply(Location input) {
+               return input.getId().equals(locationId);
+            }
+
+         });
+         return location;
+
+      } catch (NoSuchElementException e) {
+         logger.debug("couldn't match instance location %s in: %s", 
locationId, locations.get());
+         return null;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/WindowsLoginCredentialsFromEncryptedData.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/WindowsLoginCredentialsFromEncryptedData.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/WindowsLoginCredentialsFromEncryptedData.java
new file mode 100644
index 0000000..6e1b646
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/functions/WindowsLoginCredentialsFromEncryptedData.java
@@ -0,0 +1,77 @@
+/*
+ * 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.ec2.compute.functions;
+
+import static com.google.common.io.BaseEncoding.base64;
+
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.spec.KeySpec;
+
+import javax.crypto.Cipher;
+import javax.inject.Inject;
+
+import org.jclouds.crypto.Crypto;
+import org.jclouds.crypto.Pems;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.ec2.compute.domain.PasswordDataAndPrivateKey;
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.inject.Singleton;
+
+/**
+ * Given an encrypted Windows Administrator password and the decryption key, 
return a LoginCredentials instance.
+ */
+@Singleton
+public class WindowsLoginCredentialsFromEncryptedData implements 
Function<PasswordDataAndPrivateKey, LoginCredentials> {
+
+   private final Crypto crypto;
+
+   @Inject
+   public WindowsLoginCredentialsFromEncryptedData(Crypto crypto) {
+      this.crypto = crypto;
+   }
+
+   @Override
+   public LoginCredentials apply(@Nullable PasswordDataAndPrivateKey 
dataAndKey) {
+      if (dataAndKey == null)
+         return null;
+
+      try {
+         KeySpec keySpec = Pems.privateKeySpec(dataAndKey.getPrivateKey());
+         KeyFactory kf = crypto.rsaKeyFactory();
+         PrivateKey privKey = kf.generatePrivate(keySpec);
+
+         Cipher cipher = crypto.cipher("RSA");
+         cipher.init(Cipher.DECRYPT_MODE, privKey);
+         byte[] cipherText = 
base64().decode(dataAndKey.getPasswordData().getPasswordData());
+         byte[] plainText = cipher.doFinal(cipherText);
+         String password = new String(plainText, Charsets.US_ASCII);
+
+         return LoginCredentials.builder()
+                                .user("Administrator")
+                                .password(password)
+                                .noPrivateKey()
+                                .build();
+      } catch (Exception e) {
+         throw Throwables.propagate(e);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2ComputeServiceContextImpl.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2ComputeServiceContextImpl.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2ComputeServiceContextImpl.java
new file mode 100644
index 0000000..74d61c0
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2ComputeServiceContextImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ec2.compute.internal;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.Context;
+import org.jclouds.compute.Utils;
+import org.jclouds.compute.internal.ComputeServiceContextImpl;
+import org.jclouds.ec2.compute.EC2ComputeService;
+import org.jclouds.ec2.compute.EC2ComputeServiceContext;
+import org.jclouds.location.Provider;
+
+import com.google.common.reflect.TypeToken;
+
+@Singleton
+public class EC2ComputeServiceContextImpl extends ComputeServiceContextImpl 
implements EC2ComputeServiceContext {
+   @Inject
+   public EC2ComputeServiceContextImpl(@Provider Context backend, @Provider 
TypeToken<? extends Context> backendType,
+            EC2ComputeService computeService, Utils utils) {
+      super(backend, backendType, computeService, utils);
+   }
+
+   @Override
+   public EC2ComputeService getComputeService() {
+      return EC2ComputeService.class.cast(super.getComputeService());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java
new file mode 100644
index 0000000..180bd62
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java
@@ -0,0 +1,116 @@
+/*
+ * 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.ec2.compute.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.compute.strategy.GetImageStrategy;
+import org.jclouds.compute.suppliers.ImageCacheSupplier;
+import org.jclouds.domain.Location;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.util.Throwables2;
+
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
+
+   private final Supplier<LoadingCache<RegionAndName, ? extends Image>> 
lazyImageCache;
+
+   @Inject
+   protected EC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends 
Location>> locations,
+         ImageCacheSupplier images, @Memoized Supplier<Set<? extends 
Hardware>> sizes,
+         Supplier<Location> defaultLocation, @Named("DEFAULT") 
Provider<TemplateOptions> optionsProvider,
+         @Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, 
GetImageStrategy getImageStrategy,
+         Supplier<LoadingCache<RegionAndName, ? extends Image>> imageMap) {
+      super(locations, images, sizes, defaultLocation, optionsProvider, 
defaultTemplateProvider, getImageStrategy);
+      this.lazyImageCache = imageMap;
+   }
+
+   final Provider<Image> lazyImageProvider = new Provider<Image>() {
+
+      @Override
+      public Image get() {
+         if (imageId != null) {
+            String[] regionName = imageId.split("/");
+            checkArgument(regionName.length == 2,
+                  "amazon image ids must include the region ( ex. 
us-east-1/ami-7ea24a17 ) you specified: " + imageId);
+            RegionAndName key = new RegionAndName(regionName[0], 
regionName[1]);
+            try {
+               return lazyImageCache.get().get(key);
+            } catch (ExecutionException e) {
+               throw new NoSuchElementException(String.format("could not get 
imageId(%s/%s)", key.getRegion(), key.getName()));
+            } catch (UncheckedExecutionException e) {
+               // Primarily for testing: if cache is backed by a map, can get 
IllegalArgumentException instead of NPE
+               IllegalArgumentException e2 = 
Throwables2.getFirstThrowableOfType(e, IllegalArgumentException.class);
+               if (e2 != null && e2.getMessage() != null && 
e2.getMessage().contains("not present in")) {
+                  throw new 
NoSuchElementException(String.format("imageId(%s/%s) not found", 
key.getRegion(), key.getName()));
+               }
+               throw new NoSuchElementException(String.format("could not get 
imageId(%s/%s)", key.getRegion(), key.getName()));
+            } catch (CacheLoader.InvalidCacheLoadException nex) {
+               throw new NoSuchElementException(String.format("imageId(%s/%s) 
not found", key.getRegion(), key.getName()));
+            }
+         }
+         return null;
+      }
+
+   };
+
+   /**
+    * @throws NoSuchElementException
+    *            if the image is not found
+    */
+   @Override
+   protected Image resolveImage(Hardware size, Iterable<? extends Image> 
supportedImages) {
+      try {
+         return super.resolveImage(size, supportedImages);
+      } catch (NoSuchElementException e) {
+         Image returnVal = lazyImageProvider.get();
+         if (returnVal != null)
+            return returnVal;
+         throw e;
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   protected Set<? extends Image> getImages() {
+      if (imageId != null) {
+         Image image = lazyImageProvider.get();
+         return ImmutableSet.of(image);
+      } else {
+         return (Set<Image>) this.images.get();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/CreateSecurityGroupIfNeeded.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/CreateSecurityGroupIfNeeded.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/CreateSecurityGroupIfNeeded.java
new file mode 100644
index 0000000..191f965
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/CreateSecurityGroupIfNeeded.java
@@ -0,0 +1,102 @@
+/*
+ * 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.ec2.compute.loaders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
+import org.jclouds.ec2.domain.UserIdGroupPair;
+import org.jclouds.ec2.features.SecurityGroupApi;
+import org.jclouds.logging.Logger;
+import org.jclouds.net.domain.IpProtocol;
+
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public class CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndName, 
String> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+   protected final SecurityGroupApi securityClient;
+   protected final Predicate<RegionAndName> 
securityGroupEventualConsistencyDelay;
+
+   @Inject
+   public CreateSecurityGroupIfNeeded(EC2Api ec2Api,
+         @Named("SECURITY") Predicate<RegionAndName> 
securityGroupEventualConsistencyDelay) {
+      this(checkNotNull(ec2Api, "ec2Api").getSecurityGroupApi().get(), 
securityGroupEventualConsistencyDelay);
+   }
+
+   public CreateSecurityGroupIfNeeded(SecurityGroupApi securityClient,
+         @Named("SECURITY") Predicate<RegionAndName> 
securityGroupEventualConsistencyDelay) {
+      this.securityClient = checkNotNull(securityClient, "securityClient");
+      this.securityGroupEventualConsistencyDelay = 
checkNotNull(securityGroupEventualConsistencyDelay,
+            "securityGroupEventualConsistencyDelay");
+   }
+
+   @Override
+   public String load(RegionAndName from) {
+      RegionNameAndIngressRules realFrom = 
RegionNameAndIngressRules.class.cast(from);
+      createSecurityGroupInRegion(from.getRegion(), from.getName(), 
realFrom.getPorts());
+      return from.getName();
+   }
+
+   private void createSecurityGroupInRegion(String region, String name, int... 
ports) {
+      checkNotNull(region, "region");
+      checkNotNull(name, "name");
+      logger.debug(">> creating securityGroup region(%s) name(%s)", region, 
name);
+      try {
+         securityClient.createSecurityGroupInRegion(region, name, name);
+         boolean created = securityGroupEventualConsistencyDelay.apply(new 
RegionAndName(region, name));
+         if (!created)
+            throw new RuntimeException(String.format("security group %s/%s is 
not available after creating", region,
+                  name));
+         logger.debug("<< created securityGroup(%s)", name);
+         for (int port : ports) {
+            createIngressRuleForTCPPort(region, name, port);
+         }
+         if (ports.length > 0) {
+            authorizeGroupToItself(region, name);
+         }
+      } catch (IllegalStateException e) {
+         logger.debug("<< reused securityGroup(%s)", name);
+      }
+   }
+
+   protected void createIngressRuleForTCPPort(String region, String name, int 
port) {
+      logger.debug(">> authorizing securityGroup region(%s) name(%s) 
port(%s)", region, name, port);
+      securityClient.authorizeSecurityGroupIngressInRegion(region, name, 
IpProtocol.TCP, port, port, "0.0.0.0/0");
+      logger.debug("<< authorized securityGroup(%s)", name);
+   }
+
+   protected void authorizeGroupToItself(String region, String name) {
+      logger.debug(">> authorizing securityGroup region(%s) name(%s) 
permission to itself", region, name);
+      String myOwnerId = 
Iterables.get(securityClient.describeSecurityGroupsInRegion(region, name), 
0).getOwnerId();
+      securityClient.authorizeSecurityGroupIngressInRegion(region, name, new 
UserIdGroupPair(myOwnerId, name));
+      logger.debug("<< authorized securityGroup(%s)", name);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/LoadPublicIpForInstanceOrNull.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/LoadPublicIpForInstanceOrNull.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/LoadPublicIpForInstanceOrNull.java
new file mode 100644
index 0000000..dd21344
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/LoadPublicIpForInstanceOrNull.java
@@ -0,0 +1,57 @@
+/*
+ * 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.ec2.compute.loaders;
+
+import java.util.NoSuchElementException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.domain.PublicIpInstanceIdPair;
+
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public class LoadPublicIpForInstanceOrNull extends CacheLoader<RegionAndName, 
String> {
+   private final EC2Api client;
+
+   @Inject
+   public LoadPublicIpForInstanceOrNull(EC2Api client) {
+      this.client = client;
+   }
+
+   @Override
+   public String load(final RegionAndName key) throws Exception {
+      try {
+         return 
Iterables.find(client.getElasticIPAddressApi().get().describeAddressesInRegion(key.getRegion()),
+                  new Predicate<PublicIpInstanceIdPair>() {
+
+                     @Override
+                     public boolean apply(PublicIpInstanceIdPair input) {
+                        return key.getName().equals(input.getInstanceId());
+                     }
+
+                  }).getPublicIp();
+      } catch (NoSuchElementException e) {
+         return null;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/RegionAndIdToImage.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/RegionAndIdToImage.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/RegionAndIdToImage.java
new file mode 100644
index 0000000..c28d0c5
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/loaders/RegionAndIdToImage.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ec2.compute.loaders;
+
+import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.imageIds;
+
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.compute.functions.EC2ImageParser;
+import org.jclouds.logging.Logger;
+
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public class RegionAndIdToImage extends CacheLoader<RegionAndName, Image> {
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final EC2ImageParser parser;
+   private final EC2Api sync;
+
+   @Inject
+   public RegionAndIdToImage(EC2ImageParser parser, EC2Api sync) {
+      this.parser = parser;
+      this.sync = sync;
+   }
+
+   @Override
+   public Image load(RegionAndName key) throws ExecutionException {
+      try {
+         org.jclouds.ec2.domain.Image image = 
Iterables.getOnlyElement(sync.getAMIApi().get()
+               .describeImagesInRegion(key.getRegion(), 
imageIds(key.getName())));
+         return parser.apply(image);
+      } catch (Exception e) {
+         throw new ExecutionException(message(key, e), e);
+      }
+   }
+
+   public static String message(RegionAndName key, Exception e) {
+      return String.format("could not find image %s/%s: %s", key.getRegion(), 
key.getName(), e.getMessage());
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java
new file mode 100644
index 0000000..64c1ccd
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java
@@ -0,0 +1,686 @@
+/*
+ * 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.ec2.compute.options;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.emptyToNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.hash.Hashing;
+import com.google.common.primitives.Bytes;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.ec2.domain.BlockDeviceMapping;
+import org.jclouds.ec2.domain.BlockDeviceMapping.MapEBSSnapshotToDevice;
+import org.jclouds.ec2.domain.BlockDeviceMapping.MapEphemeralDeviceToDevice;
+import org.jclouds.ec2.domain.BlockDeviceMapping.MapNewVolumeToDevice;
+import org.jclouds.ec2.domain.BlockDeviceMapping.UnmapDeviceNamed;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.scriptbuilder.domain.Statement;
+
+/**
+ * Contains options supported in the {@code ComputeService#runNode} operation 
on
+ * the "ec2" provider. <h2>
+ * Usage</h2> The recommended way to instantiate a EC2TemplateOptions object is
+ * to statically import EC2TemplateOptions.* and invoke a static creation 
method
+ * followed by an instance mutator (if needed):
+ * <p/>
+ * <code>
+ * import static 
org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.*;
+ * <p/>
+ * ComputeService client = // get connection
+ * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
+ * Set<? extends NodeMetadata> set = client.createNodesInGroup(tag, 2, 
templateBuilder.build());
+ * <code>
+ */
+public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
+   @Override
+   public EC2TemplateOptions clone() {
+      EC2TemplateOptions options = new EC2TemplateOptions();
+      copyTo(options);
+      return options;
+   }
+
+   @Override
+   public void copyTo(TemplateOptions to) {
+      super.copyTo(to);
+      if (to instanceof EC2TemplateOptions) {
+         EC2TemplateOptions eTo = EC2TemplateOptions.class.cast(to);
+         if (getGroups().size() > 0)
+            eTo.securityGroups(getGroups());
+         if (getKeyPair() != null)
+            eTo.keyPair(getKeyPair());
+         if (getBlockDeviceMappings().size() > 0)
+            eTo.blockDeviceMappings(getBlockDeviceMappings());
+         if (!shouldAutomaticallyCreateKeyPair())
+            eTo.noKeyPair();
+         if (getUserData() != null)
+            eTo.userData(getUserData());
+         if (getMaxCount() > 0)
+            eTo.maxCount(getMaxCount());
+         if (getClientToken() != null)
+            eTo.clientToken(getClientToken());
+      }
+   }
+
+   private Set<String> groupNames = ImmutableSet.of();
+   private String keyPair = null;
+   private boolean noKeyPair;
+   private List<Byte> userData;
+   private ImmutableSet.Builder<BlockDeviceMapping> blockDeviceMappings = 
ImmutableSet.builder();
+   private Integer maxCount;
+   private String clientToken = null;
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+      EC2TemplateOptions that = EC2TemplateOptions.class.cast(o);
+      return super.equals(that) && equal(this.groupNames, that.groupNames) && 
equal(this.keyPair, that.keyPair)
+              && equal(this.noKeyPair, that.noKeyPair) && equal(this.userData, 
that.userData)
+              && equal(this.blockDeviceMappings, that.blockDeviceMappings)
+              && equal(this.maxCount, that.maxCount)
+              && equal(this.clientToken, that.clientToken);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects
+               .hashCode(super.hashCode(), groupNames, keyPair, noKeyPair, 
userData, userData, blockDeviceMappings,
+                       maxCount, clientToken);
+   }
+
+   @Override
+   public ToStringHelper string() {
+      ToStringHelper toString = super.string();
+      if (groupNames.size() != 0)
+         toString.add("groupNames", groupNames);
+      if (noKeyPair)
+         toString.add("noKeyPair", noKeyPair);
+      toString.add("keyPair", keyPair);
+      if (userData != null && userData.size() > 0)
+         toString.add("userDataCksum", 
Hashing.crc32().hashBytes(Bytes.toArray(userData)));
+      ImmutableSet<BlockDeviceMapping> mappings = blockDeviceMappings.build();
+      if (mappings.size() != 0)
+         toString.add("blockDeviceMappings", mappings);
+      if (maxCount != null && maxCount.intValue() > 0)
+         toString.add("maxCount", maxCount);
+      if (clientToken != null)
+         toString.add("clientToken", clientToken);
+      return toString;
+   }
+
+   public static final EC2TemplateOptions NONE = new EC2TemplateOptions();
+
+   /**
+    * 
+    * @see EC2TemplateOptions#securityGroups(Iterable<String>)
+    */
+   public EC2TemplateOptions securityGroups(String... groupNames) {
+      return securityGroups(ImmutableSet.copyOf(groupNames));
+   }
+
+   /**
+    * Specifies the security groups to be used for nodes with this template
+    */
+   public EC2TemplateOptions securityGroups(Iterable<String> groupNames) {
+      checkArgument(Iterables.size(groupNames) > 0, "you must specify at least 
one security group");
+      for (String groupId : groupNames)
+         checkNotNull(emptyToNull(groupId), "all security groups must be 
non-empty");
+      this.groupNames = ImmutableSet.copyOf(groupNames);
+      return this;
+   }
+
+   /**
+    * Unencoded data
+    */
+   public EC2TemplateOptions userData(byte[] unencodedData) {
+      checkArgument(checkNotNull(unencodedData, "unencodedData").length <= 16 
* 1024,
+            "userData cannot be larger than 16kb");
+      this.userData = Bytes.asList(unencodedData);
+      return this;
+   }
+
+   /**
+    * Specifies the keypair used to run instances with
+    */
+   public EC2TemplateOptions keyPair(String keyPair) {
+      checkState(!noKeyPair, "you cannot specify both options keyPair and 
noKeyPair");
+      this.keyPair = checkNotNull(emptyToNull(keyPair), "use noKeyPair option 
to request boot without a keypair");
+      return this;
+   }
+
+   /**
+    * Do not use a keypair on instances
+    */
+   public EC2TemplateOptions noKeyPair() {
+      checkState(keyPair == null, "you cannot specify both options keyPair and 
noKeyPair");
+      this.noKeyPair = true;
+      return this;
+   }
+
+   public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, 
String snapshotId,
+         @Nullable Integer sizeInGib, boolean deleteOnTermination) {
+      return mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, 
deleteOnTermination, null, null, false);
+   }
+
+   public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, 
String snapshotId,
+                                                        @Nullable Integer 
sizeInGib, boolean deleteOnTermination,
+                                                        @Nullable String 
volumeType, @Nullable Integer iops,
+                                                        boolean encrypted) {
+      blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, 
snapshotId, sizeInGib, deleteOnTermination,
+              volumeType, iops, encrypted));
+      return this;
+   }
+
+   public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int 
sizeInGib, boolean deleteOnTermination) {
+      return mapNewVolumeToDeviceName(deviceName, sizeInGib, 
deleteOnTermination, null, null, false);
+   }
+
+   public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int 
sizeInGib, boolean deleteOnTermination,
+                                                      @Nullable String 
volumeType, @Nullable Integer iops,
+                                                      boolean encrypted) {
+      blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, 
deleteOnTermination, volumeType,
+              iops, encrypted));
+      return this;
+   }
+
+   public EC2TemplateOptions mapEphemeralDeviceToDeviceName(String deviceName, 
String virtualName) {
+      blockDeviceMappings.add(new MapEphemeralDeviceToDevice(deviceName, 
virtualName));
+      return this;
+   }
+
+   public EC2TemplateOptions unmapDeviceNamed(String deviceName) {
+      blockDeviceMappings.add(new UnmapDeviceNamed(deviceName));
+      return this;
+   }
+
+   public EC2TemplateOptions blockDeviceMappings(Iterable<? extends 
BlockDeviceMapping> blockDeviceMappings) {
+      this.blockDeviceMappings.addAll(checkNotNull(blockDeviceMappings, 
"blockDeviceMappings"));
+      return this;
+   }
+
+   public EC2TemplateOptions maxCount(Integer maxCount) {
+      this.maxCount = maxCount;
+      return this;
+   }
+
+   public EC2TemplateOptions clientToken(String clientToken) {
+      this.clientToken = checkNotNull(clientToken, "clientToken");
+      return this;
+   }
+
+   public static class Builder extends TemplateOptions.Builder {
+      /**
+       * @see EC2TemplateOptions#blockDeviceMappings
+       */
+      public static EC2TemplateOptions blockDeviceMappings(Set<? extends 
BlockDeviceMapping> blockDeviceMappings) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.blockDeviceMappings(blockDeviceMappings);
+      }
+
+      /**
+       * @see EC2TemplateOptions#mapEBSSnapshotToDeviceName
+       */
+      public static EC2TemplateOptions mapEBSSnapshotToDeviceName(String 
deviceName, String snapshotId,
+            @Nullable Integer sizeInGib, boolean deleteOnTermination) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.mapEBSSnapshotToDeviceName(deviceName, snapshotId, 
sizeInGib, deleteOnTermination);
+      }
+
+      /**
+       * @see EC2TemplateOptions#mapNewVolumeToDeviceName
+       */
+      public static EC2TemplateOptions mapNewVolumeToDeviceName(String 
deviceName, int sizeInGib,
+            boolean deleteOnTermination) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.mapNewVolumeToDeviceName(deviceName, sizeInGib, 
deleteOnTermination);
+      }
+
+      /**
+       * @see EC2TemplateOptions#mapEphemeralDeviceToDeviceName
+       */
+      public static EC2TemplateOptions mapEphemeralDeviceToDeviceName(String 
deviceName, String virtualName) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.mapEphemeralDeviceToDeviceName(deviceName, 
virtualName);
+      }
+
+      /**
+       * @see EC2TemplateOptions#unmapDeviceNamed
+       */
+      public static EC2TemplateOptions unmapDeviceNamed(String deviceName) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.unmapDeviceNamed(deviceName);
+      }
+
+      /**
+       * @see EC2TemplateOptions#securityGroups(Iterable<String>)
+       */
+      public static EC2TemplateOptions securityGroups(String... groupNames) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return 
EC2TemplateOptions.class.cast(options.securityGroups(groupNames));
+      }
+
+      /**
+       * @see EC2TemplateOptions#securityGroups(Iterable<String>)
+       */
+      public static EC2TemplateOptions securityGroups(Iterable<String> 
groupNames) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return 
EC2TemplateOptions.class.cast(options.securityGroups(groupNames));
+      }
+
+      /**
+       * @see EC2TemplateOptions#keyPair
+       */
+      public static EC2TemplateOptions keyPair(String keyPair) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.keyPair(keyPair));
+      }
+
+      /**
+       * @see EC2TemplateOptions#userData
+       */
+      public static EC2TemplateOptions userData(byte[] unencodedData) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.userData(unencodedData));
+      }
+
+      /**
+       * @see EC2TemplateOptions#noKeyPair
+       */
+      public static EC2TemplateOptions noKeyPair() {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.noKeyPair());
+      }
+
+      // methods that only facilitate returning the correct object type
+      /**
+       * @see TemplateOptions#inboundPorts
+       */
+      public static EC2TemplateOptions inboundPorts(int... ports) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.inboundPorts(ports));
+      }
+
+      /**
+       * @see TemplateOptions#port
+       */
+      public static EC2TemplateOptions blockOnPort(int port, int seconds) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.blockOnPort(port, 
seconds));
+      }
+
+      /**
+       * @see TemplateOptions#installPrivateKey
+       */
+      public static EC2TemplateOptions installPrivateKey(String rsaKey) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return 
EC2TemplateOptions.class.cast(options.installPrivateKey(rsaKey));
+      }
+
+      /**
+       * @see TemplateOptions#authorizePublicKey
+       */
+      public static EC2TemplateOptions authorizePublicKey(String rsaKey) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return 
EC2TemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
+      }
+
+      /**
+       * @see TemplateOptions#userMetadata(Map)
+       */
+      public static EC2TemplateOptions userMetadata(Map<String, String> 
userMetadata) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return 
EC2TemplateOptions.class.cast(options.userMetadata(userMetadata));
+      }
+
+      /**
+       * @see TemplateOptions#nodeNames(Iterable)
+       */
+      public static EC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.nodeNames(nodeNames));
+      }
+
+      /**
+       * @see TemplateOptions#networks(Iterable)
+       */
+      public static EC2TemplateOptions networks(Iterable<String> networks) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return EC2TemplateOptions.class.cast(options.networks(networks));
+      }
+
+      public static EC2TemplateOptions overrideLoginUser(String user) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.overrideLoginUser(user);
+      }
+
+      public static EC2TemplateOptions overrideLoginPassword(String password) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.overrideLoginPassword(password);
+      }
+
+      public static EC2TemplateOptions overrideLoginPrivateKey(String 
privateKey) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.overrideLoginPrivateKey(privateKey);
+      }
+
+      public static EC2TemplateOptions overrideAuthenticateSudo(boolean 
authenticateSudo) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.overrideAuthenticateSudo(authenticateSudo);
+      }
+
+      public static EC2TemplateOptions 
overrideLoginCredentials(LoginCredentials credentials) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.overrideLoginCredentials(credentials);
+      }
+
+      public static EC2TemplateOptions nameTask(String name) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.nameTask(name);
+      }
+
+      public static EC2TemplateOptions runAsRoot(boolean value) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.runAsRoot(value);
+      }
+
+      public static EC2TemplateOptions tags(Iterable<String> tags) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.tags(tags);
+      }
+
+      public static EC2TemplateOptions blockUntilRunning(boolean 
blockUntilRunning) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.blockUntilRunning(blockUntilRunning);
+      }
+
+      public static EC2TemplateOptions runScript(Statement script) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.runScript(script);
+      }
+      
+      public static EC2TemplateOptions runScript(String script) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.runScript(script);
+      }
+
+      public static EC2TemplateOptions userMetadata(String key, String value) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.userMetadata(key, value);
+      }
+
+      public static EC2TemplateOptions blockOnComplete(boolean value) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.blockOnComplete(value);
+      }
+
+      public static EC2TemplateOptions maxCount(Integer maxCount) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.maxCount(maxCount);
+      }
+
+      public static EC2TemplateOptions clientToken(String clientToken) {
+         EC2TemplateOptions options = new EC2TemplateOptions();
+         return options.clientToken(clientToken);
+      }
+   }
+
+   // methods that only facilitate returning the correct object type
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions blockOnPort(int port, int seconds) {
+      return EC2TemplateOptions.class.cast(super.blockOnPort(port, seconds));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions inboundPorts(int... ports) {
+      return EC2TemplateOptions.class.cast(super.inboundPorts(ports));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions authorizePublicKey(String publicKey) {
+      return 
EC2TemplateOptions.class.cast(super.authorizePublicKey(publicKey));
+   }
+   
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions installPrivateKey(String privateKey) {
+      return 
EC2TemplateOptions.class.cast(super.installPrivateKey(privateKey));
+   }
+   
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions blockUntilRunning(boolean blockUntilRunning) {
+      return 
EC2TemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions dontAuthorizePublicKey() {
+      return EC2TemplateOptions.class.cast(super.dontAuthorizePublicKey());
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions nameTask(String name) {
+      return EC2TemplateOptions.class.cast(super.nameTask(name));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions runAsRoot(boolean runAsRoot) {
+      return EC2TemplateOptions.class.cast(super.runAsRoot(runAsRoot));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions runScript(Statement script) {
+      return EC2TemplateOptions.class.cast(super.runScript(script));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions overrideLoginCredentials(LoginCredentials 
overridingCredentials) {
+      return 
EC2TemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions overrideLoginPassword(String password) {
+      return 
EC2TemplateOptions.class.cast(super.overrideLoginPassword(password));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions overrideLoginPrivateKey(String privateKey) {
+      return 
EC2TemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions overrideLoginUser(String loginUser) {
+      return EC2TemplateOptions.class.cast(super.overrideLoginUser(loginUser));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions overrideAuthenticateSudo(boolean 
authenticateSudo) {
+      return 
EC2TemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions userMetadata(Map<String, String> userMetadata) {
+      return EC2TemplateOptions.class.cast(super.userMetadata(userMetadata));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions userMetadata(String key, String value) {
+      return EC2TemplateOptions.class.cast(super.userMetadata(key, value));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
+      return EC2TemplateOptions.class.cast(super.nodeNames(nodeNames));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions networks(Iterable<String> networks) {
+      return EC2TemplateOptions.class.cast(super.networks(networks));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions runScript(String script) {
+      return EC2TemplateOptions.class.cast(super.runScript(script));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions tags(Iterable<String> tags) {
+      return EC2TemplateOptions.class.cast(super.tags(tags));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions wrapInInitScript(boolean wrapInInitScript) {
+      return 
EC2TemplateOptions.class.cast(super.wrapInInitScript(wrapInInitScript));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EC2TemplateOptions blockOnComplete(boolean blockOnComplete) {
+      return 
EC2TemplateOptions.class.cast(super.blockOnComplete(blockOnComplete));
+   }
+   
+   /**
+    * @return groupNames the user specified to run instances with, or zero
+    *         length set to create an implicit group
+    */
+   public Set<String> getGroups() {
+      return groupNames;
+   }
+
+   /**
+    * @return keyPair to use when running the instance or null, to generate a
+    *         keypair.
+    */
+   public String getKeyPair() {
+      return keyPair;
+   }
+
+   /**
+    * @return true (default) if we are supposed to use a keypair
+    */
+   public boolean shouldAutomaticallyCreateKeyPair() {
+      return !noKeyPair;
+   }
+
+   /**
+    * @return unencoded user data.
+    */
+   public byte[] getUserData() {
+      return userData == null ? null : Bytes.toArray(userData);
+   }
+
+   /**
+    * @return BlockDeviceMapping to use when running the instance or null.
+    */
+   public Set<BlockDeviceMapping> getBlockDeviceMappings() {
+      return blockDeviceMappings.build();
+   }
+
+   /**
+    * @return the maximum number of instances to create
+    */
+   public int getMaxCount() {
+      return maxCount != null ? maxCount.intValue() : 0;
+   }
+
+   /**
+    * See <a 
href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Run_Instance_Idempotency.html";>here</a>
 for more information.
+    *
+    * @return the optional client token string, used for idempotency
+    */
+   public String getClientToken() {
+      return clientToken;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java
new file mode 100644
index 0000000..46808fa
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ec2.compute.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.predicates.ImagePredicates;
+import org.jclouds.ec2.domain.RootDeviceType;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for image filters (predicates).
+ * 
+ * This class has static methods that create customized predicates to use with
+ * {@link org.jclouds.compute.ComputeService}.
+ */
+public class EC2ImagePredicates {
+
+   /**
+    * evaluates true if the Image has the specified root device type
+    * 
+    * @param rootDeviceType
+    *           rootDeviceType of the images
+    * @return predicate
+    */
+   public static Predicate<Image> rootDeviceType(final RootDeviceType 
rootDeviceType) {
+      checkNotNull(rootDeviceType, "rootDeviceType must be defined");
+      return ImagePredicates.userMetadataContains("rootDeviceType", 
rootDeviceType.value());
+   }
+
+  
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
new file mode 100644
index 0000000..7899478
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ec2.compute.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.ec2.EC2Api;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.domain.SecurityGroup;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+
+@Singleton
+public class SecurityGroupPresent implements Predicate<RegionAndName> {
+
+   private final EC2Api client;
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   @Inject
+   public SecurityGroupPresent(EC2Api client) {
+      this.client = checkNotNull(client, "client");
+   }
+
+   public boolean apply(RegionAndName securityGroup) {
+      logger.trace("looking for security group %s/%s", 
securityGroup.getRegion(), securityGroup.getName());
+      try {
+         return refresh(securityGroup) != null;
+      } catch (ResourceNotFoundException e) {
+         return false;
+      } catch (NoSuchElementException e) {
+         return false;
+      }
+   }
+
+   protected SecurityGroup refresh(RegionAndName securityGroup) {
+      return 
Iterables.getOnlyElement(client.getSecurityGroupApi().get().describeSecurityGroupsInRegion(
+            securityGroup.getRegion(), securityGroup.getName()));
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/397d9926/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java
----------------------------------------------------------------------
diff --git 
a/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java
 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java
new file mode 100644
index 0000000..454172c
--- /dev/null
+++ 
b/dependencies/jclouds/apis/ec2/1.8.0-stratos/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java
@@ -0,0 +1,199 @@
+/*
+ * 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.ec2.compute.strategy;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.ssh.SshKeys.fingerprintPrivateKey;
+import static org.jclouds.ssh.SshKeys.sha1PrivateKey;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.inject.Inject;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.functions.GroupNamingConvention.Factory;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
+import org.jclouds.ec2.compute.options.EC2TemplateOptions;
+import org.jclouds.ec2.domain.BlockDeviceMapping;
+import org.jclouds.ec2.domain.KeyPair;
+import org.jclouds.ec2.options.RunInstancesOptions;
+import org.jclouds.javax.annotation.Nullable;
+
+@Singleton
+public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
+   @VisibleForTesting
+   public Function<RegionAndName, KeyPair> makeKeyPair;
+   @VisibleForTesting
+   public final ConcurrentMap<RegionAndName, KeyPair> credentialsMap;
+   @VisibleForTesting
+   public final LoadingCache<RegionAndName, String> securityGroupMap;
+   @VisibleForTesting
+   public final Provider<RunInstancesOptions> optionsProvider;
+   private final Factory namingConvention;
+
+   @Inject
+   public 
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(Function<RegionAndName,
 KeyPair> makeKeyPair,
+            ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
+            @Named("SECURITY") LoadingCache<RegionAndName, String> 
securityGroupMap,
+            Provider<RunInstancesOptions> optionsProvider,
+            GroupNamingConvention.Factory namingConvention) {
+      this.makeKeyPair = checkNotNull(makeKeyPair, "makeKeyPair");
+      this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
+      this.securityGroupMap = checkNotNull(securityGroupMap, 
"securityGroupMap");
+      this.optionsProvider = checkNotNull(optionsProvider, "optionsProvider");
+      this.namingConvention = checkNotNull(namingConvention, 
"namingConvention");
+   }
+
+   public RunInstancesOptions execute(String region, String group, Template 
template) {
+
+      RunInstancesOptions instanceOptions = 
getOptionsProvider().get().asType(template.getHardware().getId());
+
+      String keyPairName = 
createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, 
template.getOptions());
+
+      addSecurityGroups(region, group, template, instanceOptions);
+      if (template.getOptions() instanceof EC2TemplateOptions) {
+
+         if (keyPairName != null)
+            instanceOptions.withKeyName(keyPairName);
+
+         byte[] userData = 
EC2TemplateOptions.class.cast(template.getOptions()).getUserData();
+
+         if (userData != null)
+            instanceOptions.withUserData(userData);
+
+         Set<BlockDeviceMapping> blockDeviceMappings = 
EC2TemplateOptions.class.cast(template.getOptions())
+                  .getBlockDeviceMappings();
+         if (blockDeviceMappings.size() > 0) {
+            
checkState("ebs".equals(template.getImage().getUserMetadata().get("rootDeviceType")),
+                     "BlockDeviceMapping only available on ebs boot");
+            instanceOptions.withBlockDeviceMappings(blockDeviceMappings);
+         }
+
+         String clientToken = 
EC2TemplateOptions.class.cast(template.getOptions()).getClientToken();
+
+         if (clientToken != null) {
+            instanceOptions.withClientToken(clientToken);
+         }
+      }
+      return instanceOptions;
+   }
+
+   protected void addSecurityGroups(String region, String group, Template 
template, RunInstancesOptions instanceOptions) {
+      Set<String> groups = getSecurityGroupsForTagAndOptions(region, group, 
template.getOptions());
+      instanceOptions.withSecurityGroups(groups);
+   }
+
+   @VisibleForTesting
+   public String createNewKeyPairUnlessUserSpecifiedOtherwise(String region, 
String group, TemplateOptions options) {
+      String keyPairName = null;
+      boolean shouldAutomaticallyCreateKeyPair = true;
+
+      if (options instanceof EC2TemplateOptions) {
+         keyPairName = EC2TemplateOptions.class.cast(options).getKeyPair();
+         if (keyPairName == null)
+            shouldAutomaticallyCreateKeyPair = 
EC2TemplateOptions.class.cast(options)
+                     .shouldAutomaticallyCreateKeyPair();
+      }
+
+      if (keyPairName == null && shouldAutomaticallyCreateKeyPair) {
+         keyPairName = createOrImportKeyPair(region, group, options);
+      } else if (keyPairName != null) {
+         if (options.getLoginPrivateKey() != null) {
+            String pem = options.getLoginPrivateKey();
+            KeyPair keyPair = 
KeyPair.builder().region(region).keyName(keyPairName).fingerprint(
+                     
fingerprintPrivateKey(pem)).sha1OfPrivateKey(sha1PrivateKey(pem)).keyMaterial(pem).build();
+            RegionAndName key = new RegionAndName(region, keyPairName);
+            credentialsMap.put(key, keyPair);
+         }
+      }
+
+      if (options.getRunScript() != null) {
+         RegionAndName regionAndName = new RegionAndName(region, keyPairName);
+         checkArgument(
+                  credentialsMap.containsKey(regionAndName),
+                  "no private key configured for: %s; please use 
options.overrideLoginCredentialWith(rsa_private_text)",
+                  regionAndName);
+      }
+      return keyPairName;
+   }
+
+   // base EC2 driver currently does not support key import
+   protected String createOrImportKeyPair(String region, String group, 
TemplateOptions options) {
+      RegionAndName regionAndGroup = new RegionAndName(region, group);
+      KeyPair keyPair;
+      // make sure that we don't request multiple keys simultaneously
+      synchronized (credentialsMap) {
+         // if there is already a keypair for the group specified, use it
+         if (credentialsMap.containsKey(regionAndGroup))
+            return credentialsMap.get(regionAndGroup).getKeyName();
+
+         // otherwise create a new keypair and key it under the group and also 
the regular keyname
+         keyPair = makeKeyPair.apply(new RegionAndName(region, group));
+         credentialsMap.put(regionAndGroup, keyPair);
+      }
+      credentialsMap.put(new RegionAndName(region, keyPair.getKeyName()), 
keyPair);
+      return keyPair.getKeyName();
+   }
+
+   @VisibleForTesting
+   public Set<String> getSecurityGroupsForTagAndOptions(String region, 
@Nullable String group, TemplateOptions options) {
+      Builder<String> groups = ImmutableSet.builder();
+
+      if (group != null) {
+         String markerGroup = 
namingConvention.create().sharedNameForGroup(group);
+
+         groups.add(markerGroup);
+
+         RegionNameAndIngressRules regionNameAndIngressRulesForMarkerGroup;
+
+         if (userSpecifiedTheirOwnGroups(options)) {
+            regionNameAndIngressRulesForMarkerGroup = new 
RegionNameAndIngressRules(region, markerGroup, new int[] {},
+                     false);
+            groups.addAll(EC2TemplateOptions.class.cast(options).getGroups());
+         } else {
+            regionNameAndIngressRulesForMarkerGroup = new 
RegionNameAndIngressRules(region, markerGroup, options
+                     .getInboundPorts(), true);
+         }
+         // this will create if not yet exists.
+         
securityGroupMap.getUnchecked(regionNameAndIngressRulesForMarkerGroup);
+      }
+      return groups.build();
+   }
+
+   protected boolean userSpecifiedTheirOwnGroups(TemplateOptions options) {
+      return options instanceof EC2TemplateOptions && 
EC2TemplateOptions.class.cast(options).getGroups().size() > 0;
+   }
+
+   // allows us to mock this method
+   @VisibleForTesting
+   public javax.inject.Provider<RunInstancesOptions> getOptionsProvider() {
+      return optionsProvider;
+   }
+}

Reply via email to