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; + } +}
