added iam instance profile args to aws-ec2

This commit is contained in:
Adrian Cole 2013-02-25 17:35:02 -08:00
parent ac7a4b5354
commit 1fbc47bd77
32 changed files with 738 additions and 53 deletions

View File

@ -366,6 +366,7 @@ Here's an example of creating and running a small linux node in the group webser
:key-pair
;; aws-ec2
:placement-group :subnet-id :spot-price :spot-options
:iam-instance-profile-name :iam-instance-profile-arn
;; cloudstack aws-ec2
:security-group-ids
;; softlayer

View File

@ -35,7 +35,7 @@
<properties>
<test.aws-ec2.endpoint>https://ec2.us-east-1.amazonaws.com</test.aws-ec2.endpoint>
<test.aws-ec2.api-version>2011-05-15</test.aws-ec2.api-version>
<test.aws-ec2.api-version>2012-06-01</test.aws-ec2.api-version>
<test.aws-ec2.build-version />
<test.aws-ec2.identity>${test.aws.identity}</test.aws-ec2.identity>
<test.aws-ec2.credential>${test.aws.credential}</test.aws-ec2.credential>
@ -68,6 +68,12 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.labs</groupId>
<artifactId>aws-iam</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.provider</groupId>
<artifactId>aws-cloudwatch</artifactId>

View File

@ -27,6 +27,7 @@ import java.util.Map.Entry;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.LaunchSpecification.IAMInstanceProfileRequest;
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
@ -78,7 +79,13 @@ public class BindLaunchSpecificationToFormParams implements Binder, Function<Lau
options.enableMonitoring();
if (launchSpec.getUserData() != null)
options.withUserData(launchSpec.getUserData());
if (launchSpec.getIAMInstanceProfile().isPresent()) {
IAMInstanceProfileRequest profile = launchSpec.getIAMInstanceProfile().get();
if (profile.getArn().isPresent())
options.withIAMInstanceProfileArn(profile.getArn().get());
if (profile.getName().isPresent())
options.withIAMInstanceProfileName(profile.getName().get());
}
for (Entry<String, String> entry : options.buildFormParameters().entries()) {
builder.put("LaunchSpecification." + entry.getKey(), entry.getValue());
}

View File

@ -33,6 +33,7 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.annotations.SinceApiVersion;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.base.Objects;
@ -72,6 +73,10 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
AWSEC2TemplateOptions eTo = AWSEC2TemplateOptions.class.cast(to);
if (getSubnetId() != null)
eTo.subnetId(getSubnetId());
if (getIAMInstanceProfileArn() != null)
eTo.iamInstanceProfileArn(getIAMInstanceProfileArn());
if (getIAMInstanceProfileName() != null)
eTo.iamInstanceProfileName(getIAMInstanceProfileName());
if (isMonitoringEnabled())
eTo.enableMonitoring();
if (!shouldAutomaticallyCreatePlacementGroup())
@ -94,6 +99,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
private Float spotPrice;
private RequestSpotInstancesOptions spotOptions = RequestSpotInstancesOptions.NONE;
private Set<String> groupIds = ImmutableSet.of();
private String iamInstanceProfileArn;
private String iamInstanceProfileName;
@Override
public boolean equals(Object o) {
@ -106,13 +113,14 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
&& equal(this.placementGroup, that.placementGroup)
&& equal(this.noPlacementGroup, that.noPlacementGroup) && equal(this.subnetId, that.subnetId)
&& equal(this.spotPrice, that.spotPrice) && equal(this.spotOptions, that.spotOptions)
&& equal(this.groupIds, that.groupIds);
&& equal(this.groupIds, that.groupIds) && equal(this.iamInstanceProfileArn, that.iamInstanceProfileArn)
&& equal(this.iamInstanceProfileName, that.iamInstanceProfileName);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), monitoringEnabled, placementGroup, noPlacementGroup, subnetId,
spotPrice, spotOptions, groupIds);
spotPrice, spotOptions, groupIds, iamInstanceProfileArn, iamInstanceProfileName);
}
@Override
@ -129,6 +137,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
toString.add("spotOptions", spotOptions);
if (groupIds.size() != 0)
toString.add("groupIds", groupIds);
toString.add("iamInstanceProfileArn", iamInstanceProfileArn);
toString.add("iamInstanceProfileName", iamInstanceProfileName);
return toString;
}
@ -171,6 +181,24 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
return this;
}
/**
* @see org.jclouds.aws.ec2.options.AWSRunInstancesOptions#withIAMInstanceProfileArn(String)
*/
@SinceApiVersion("2012-06-01")
public AWSEC2TemplateOptions iamInstanceProfileArn(String arn) {
this.iamInstanceProfileArn = checkNotNull(emptyToNull(arn), "arn must be defined");
return this;
}
/**
* @see org.jclouds.aws.ec2.options.AWSRunInstancesOptions#withIAMInstanceProfileName(String)
*/
@SinceApiVersion("2012-06-01")
public AWSEC2TemplateOptions iamInstanceProfileName(String name) {
this.iamInstanceProfileName = checkNotNull(emptyToNull(name), "name must be defined");
return this;
}
/**
* Specifies the maximum spot price to use
*/
@ -393,7 +421,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
}
/**
* @see TemplateOptions#spotPrice
* @see AWSEC2TemplateOptions#subnetId
*/
public static AWSEC2TemplateOptions subnetId(String subnetId) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
@ -401,7 +429,25 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
}
/**
* @see TemplateOptions#spotPrice
* @see AWSEC2TemplateOptions#iamInstanceProfileArn
*/
@SinceApiVersion("2012-06-01")
public static AWSEC2TemplateOptions iamInstanceProfileArn(String arn) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.iamInstanceProfileArn(arn);
}
/**
* @see AWSEC2TemplateOptions#iamInstanceProfileName
*/
@SinceApiVersion("2012-06-01")
public static AWSEC2TemplateOptions iamInstanceProfileName(String name) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.iamInstanceProfileName(name);
}
/**
* @see AWSEC2TemplateOptions#spotPrice
*/
public static AWSEC2TemplateOptions spotPrice(Float spotPrice) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
@ -409,7 +455,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
}
/**
* @see TemplateOptions#spotOptions
* @see AWSEC2TemplateOptions#spotOptions
*/
public static AWSEC2TemplateOptions spotOptions(RequestSpotInstancesOptions spotOptions) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
@ -431,6 +477,11 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return AWSEC2TemplateOptions.class.cast(options.userMetadata(key, value));
}
public static AWSEC2TemplateOptions blockUntilRunning(boolean blockUntilRunning) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.blockUntilRunning(blockUntilRunning);
}
}
// methods that only facilitate returning the correct object type
@ -690,4 +741,23 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
return spotOptions;
}
/**
* The Amazon resource name (ARN) of the IAM Instance Profile (IIP) to associate with the instance.
*
* @see org.jclouds.aws.ec2.options.AWSRunInstancesOptions#withIAMInstanceProfileArn(String)
*/
@SinceApiVersion("2012-06-01")
public String getIAMInstanceProfileArn() {
return iamInstanceProfileArn;
}
/**
* The name of the IAM Instance Profile (IIP) to associate with the instance.
*
* @see org.jclouds.aws.ec2.options.AWSRunInstancesOptions#withIAMInstanceProfileName(String)
*/
@SinceApiVersion("2012-06-01")
public String getIAMInstanceProfileName() {
return iamInstanceProfileName;
}
}

View File

@ -99,7 +99,8 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
AWSEC2TemplateOptions awsOptions = AWSEC2TemplateOptions.class.cast(template.getOptions());
LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder()
.imageId(template.getImage().getProviderId()).availabilityZone(zone).subnetId(awsOptions.getSubnetId())
.build();
.iamInstanceProfileArn(awsOptions.getIAMInstanceProfileArn())
.iamInstanceProfileName(awsOptions.getIAMInstanceProfileName()).build();
RequestSpotInstancesOptions options = awsOptions.getSpotOptions();
if (logger.isDebugEnabled())
logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region,

View File

@ -91,8 +91,13 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
if (placementGroupName != null)
instanceOptions.inPlacementGroup(placementGroupName);
if (AWSEC2TemplateOptions.class.cast(template.getOptions()).isMonitoringEnabled())
AWSEC2TemplateOptions awsTemplateOptions = AWSEC2TemplateOptions.class.cast(template.getOptions());
if (awsTemplateOptions.isMonitoringEnabled())
instanceOptions.enableMonitoring();
if (awsTemplateOptions.getIAMInstanceProfileArn() != null)
instanceOptions.withIAMInstanceProfileArn(awsTemplateOptions.getIAMInstanceProfileArn());
if (awsTemplateOptions.getIAMInstanceProfileName() != null)
instanceOptions.withIAMInstanceProfileName(awsTemplateOptions.getIAMInstanceProfileName());
return instanceOptions;
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
@ -30,8 +32,11 @@ import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.annotations.SinceApiVersion;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
@ -64,6 +69,8 @@ public class AWSRunningInstance extends RunningInstance {
private String vpcId;
private Hypervisor hypervisor;
private Map<String, String> securityGroupIdToNames = Maps.newLinkedHashMap();
private String iamInstanceProfileArn;
private String iamInstanceProfileId;
public Builder securityGroupIdToNames(Map<String, String> securityGroupIdToNames) {
this.securityGroupIdToNames = ImmutableMap.copyOf(checkNotNull(securityGroupIdToNames,
@ -118,13 +125,34 @@ public class AWSRunningInstance extends RunningInstance {
return this;
}
/**
* @see AWSRunningInstance#getIAMInstanceProfile()
*/
public Builder iamInstanceProfileArn(String iamInstanceProfileArn) {
this.iamInstanceProfileArn = iamInstanceProfileArn;
return this;
}
/**
* @see AWSRunningInstance#getIAMInstanceProfile()
*/
public Builder iamInstanceProfileId(String iamInstanceProfileId) {
this.iamInstanceProfileId = iamInstanceProfileId;
return this;
}
@Override
public AWSRunningInstance build() {
Optional<IAMInstanceProfile> iamInstanceProfile = Optional.absent();
if (iamInstanceProfileArn != null && iamInstanceProfileId != null) {
iamInstanceProfile = Optional.of(IAMInstanceProfile.forArnAndId(iamInstanceProfileArn,
iamInstanceProfileId));
}
return new AWSRunningInstance(region, securityGroupIdToNames, amiLaunchIndex, dnsName, imageId, instanceId,
instanceState, rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone,
virtualizationType, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType,
rootDeviceName, ebsBlockDevices, monitoringState, placementGroup, productCodes, subnetId,
spotInstanceRequestId, vpcId, hypervisor, tags);
spotInstanceRequestId, vpcId, hypervisor, tags, iamInstanceProfile);
}
@Override
@ -136,6 +164,10 @@ public class AWSRunningInstance extends RunningInstance {
.productCodes(awsIn.productCodes).subnetId(awsIn.subnetId)
.spotInstanceRequestId(awsIn.spotInstanceRequestId).vpcId(awsIn.vpcId).hypervisor(awsIn.hypervisor)
.securityGroupIdToNames(awsIn.securityGroupIdToNames);
if (awsIn.getIAMInstanceProfile().isPresent()) {
iamInstanceProfileArn(awsIn.getIAMInstanceProfile().get().getArn());
iamInstanceProfileId(awsIn.getIAMInstanceProfile().get().getId());
}
}
return this;
}
@ -159,6 +191,7 @@ public class AWSRunningInstance extends RunningInstance {
private final String vpcId;
private final Hypervisor hypervisor;
private final Map<String, String> securityGroupIdToNames;
private final Optional<IAMInstanceProfile> iamInstanceProfile;
protected AWSRunningInstance(String region, Map<String, String> securityGroupIdToNames, String amiLaunchIndex,
String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState,
@ -167,7 +200,7 @@ public class AWSRunningInstance extends RunningInstance {
String privateIpAddress, String ramdiskId, String reason, RootDeviceType rootDeviceType,
String rootDeviceName, Map<String, BlockDevice> ebsBlockDevices, MonitoringState monitoringState,
String placementGroup, Iterable<String> productCodes, String subnetId, String spotInstanceRequestId,
String vpcId, Hypervisor hypervisor, Map<String, String> tags) {
String vpcId, Hypervisor hypervisor, Map<String, String> tags, Optional<IAMInstanceProfile> iamInstanceProfile) {
super(region, securityGroupIdToNames.values(), amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType,
platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName,
@ -181,6 +214,7 @@ public class AWSRunningInstance extends RunningInstance {
this.hypervisor = checkNotNull(hypervisor, "hypervisor");
this.securityGroupIdToNames = ImmutableMap.<String, String> copyOf(checkNotNull(securityGroupIdToNames,
"securityGroupIdToNames"));
this.iamInstanceProfile = checkNotNull(iamInstanceProfile, "iamInstanceProfile of %s", instanceId);
}
public Map<String, String> getSecurityGroupIdToNames() {
@ -240,11 +274,66 @@ public class AWSRunningInstance extends RunningInstance {
return subnetId;
}
/**
* The IAM Instance Profile (IIP) associated with the instance.
*/
@SinceApiVersion("2012-06-01")
public Optional<IAMInstanceProfile> getIAMInstanceProfile() {
return iamInstanceProfile;
}
@Override
protected ToStringHelper string() {
return super.string().add("monitoringState", monitoringState).add("placementGroup", placementGroup)
.add("subnetId", subnetId).add("spotInstanceRequestId", spotInstanceRequestId).add("vpcId", vpcId)
.add("hypervisor", hypervisor);
.add("hypervisor", hypervisor).add("iamInstanceProfile", iamInstanceProfile.orNull());
}
public static class IAMInstanceProfile {
public static IAMInstanceProfile forArnAndId(String arn, String id) {
return new IAMInstanceProfile(arn, id);
}
private final String arn;
private final String id;
private IAMInstanceProfile(String arn, String id) {
this.arn = checkNotNull(arn, "arn");
this.id = checkNotNull(id, "id for %s", arn);
}
/**
* The Amazon resource name (ARN) of the IAM Instance Profile (IIP) to associate with the instance.
*/
public String getArn() {
return arn;
}
/**
* The ID of the IAM Instance Profile ID (IIP) associated with the instance.
*/
public String getId() {
return id;
}
@Override
public int hashCode() {
return Objects.hashCode(arn, id);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
IAMInstanceProfile that = IAMInstanceProfile.class.cast(obj);
return equal(this.arn, that.arn) && equal(this.id, that.id);
}
@Override
public String toString() {
return toStringHelper("").add("arn", arn).add("id", id).toString();
}
}
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Arrays;
@ -29,7 +31,10 @@ import org.jclouds.ec2.domain.BlockDeviceMapping.MapEBSSnapshotToDevice;
import org.jclouds.ec2.domain.BlockDeviceMapping.MapEphemeralDeviceToDevice;
import org.jclouds.ec2.domain.BlockDeviceMapping.MapNewVolumeToDevice;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.annotations.SinceApiVersion;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
@ -62,6 +67,8 @@ public class LaunchSpecification {
protected ImmutableSet.Builder<String> securityGroupIds = ImmutableSet.builder();
protected ImmutableSet.Builder<String> securityGroupNames = ImmutableSet.builder();
protected byte[] userData;
private String iamInstanceProfileArn;
private String iamInstanceProfileName;
public void clear() {
securityGroupIdToNames = ImmutableMap.builder();
@ -77,6 +84,8 @@ public class LaunchSpecification {
securityGroupIds = ImmutableSet.builder();
securityGroupNames = ImmutableSet.builder();
userData = null;
iamInstanceProfileArn = null;
iamInstanceProfileName = null;
}
public Builder securityGroupIdToNames(Map<String, String> securityGroupIdToNames) {
@ -183,19 +192,52 @@ public class LaunchSpecification {
return this;
}
/**
* @see LaunchSpecification#getIAMInstanceProfile()
*/
public Builder iamInstanceProfileArn(String iamInstanceProfileArn) {
this.iamInstanceProfileArn = iamInstanceProfileArn;
return this;
}
/**
* @see LaunchSpecification#getIAMInstanceProfile()
*/
public Builder iamInstanceProfileName(String iamInstanceProfileName) {
this.iamInstanceProfileName = iamInstanceProfileName;
return this;
}
public LaunchSpecification build() {
Optional<IAMInstanceProfileRequest> iamInstanceProfile;
if (iamInstanceProfileArn != null && iamInstanceProfileName != null) {
iamInstanceProfile = Optional.of(IAMInstanceProfileRequest.forArnAndName(iamInstanceProfileArn,
iamInstanceProfileName));
} else if (iamInstanceProfileArn != null) {
iamInstanceProfile = Optional.of(IAMInstanceProfileRequest.forArn(iamInstanceProfileArn));
} else if (iamInstanceProfileName != null) {
iamInstanceProfile = Optional.of(IAMInstanceProfileRequest.forName(iamInstanceProfileName));
} else {
iamInstanceProfile = Optional.absent();
}
return new LaunchSpecification(instanceType, imageId, kernelId, ramdiskId, availabilityZone, subnetId,
keyName, securityGroupIdToNames.build(), blockDeviceMappings.build(), monitoringEnabled,
securityGroupIds.build(), securityGroupNames.build(), userData);
securityGroupIds.build(), securityGroupNames.build(), userData, iamInstanceProfile);
}
public static Builder fromLaunchSpecification(LaunchSpecification in) {
return new Builder().instanceType(in.getInstanceType()).imageId(in.getImageId()).kernelId(in.getKernelId())
Builder builder = new Builder();
builder.instanceType(in.getInstanceType()).imageId(in.getImageId()).kernelId(in.getKernelId())
.ramdiskId(in.getRamdiskId()).availabilityZone(in.getAvailabilityZone()).subnetId(in.getSubnetId())
.keyName(in.getKeyName()).securityGroupIdToNames(in.getSecurityGroupIdToNames())
.securityGroupIds(in.getSecurityGroupIds()).securityGroupNames(in.getSecurityGroupNames())
.blockDeviceMappings(in.getBlockDeviceMappings()).monitoringEnabled(in.isMonitoringEnabled())
.userData(in.getUserData());
if (in.getIAMInstanceProfile().isPresent()) {
builder.iamInstanceProfileArn(in.getIAMInstanceProfile().get().getArn().orNull());
builder.iamInstanceProfileName(in.getIAMInstanceProfile().get().getName().orNull());
}
return builder;
}
}
@ -212,11 +254,13 @@ public class LaunchSpecification {
protected final Set<String> securityGroupNames;
protected final Boolean monitoringEnabled;
protected final byte[] userData;
protected final Optional<IAMInstanceProfileRequest> iamInstanceProfile;
public LaunchSpecification(String instanceType, String imageId, String kernelId, String ramdiskId,
String availabilityZone, String subnetId, String keyName, Map<String, String> securityGroupIdToNames,
Iterable<? extends BlockDeviceMapping> blockDeviceMappings, Boolean monitoringEnabled,
Set<String> securityGroupIds, Set<String> securityGroupNames, byte[] userData) {
Set<String> securityGroupIds, Set<String> securityGroupNames, byte[] userData,
Optional<IAMInstanceProfileRequest> iamInstanceProfile) {
this.instanceType = checkNotNull(instanceType, "instanceType");
this.imageId = checkNotNull(imageId, "imageId");
this.kernelId = kernelId;
@ -230,6 +274,7 @@ public class LaunchSpecification {
this.securityGroupNames = ImmutableSortedSet.copyOf(checkNotNull(securityGroupNames, "securityGroupNames"));
this.monitoringEnabled = monitoringEnabled;
this.userData = userData;
this.iamInstanceProfile = checkNotNull(iamInstanceProfile, "iamInstanceProfile");
}
public Map<String, String> getSecurityGroupIdToNames() {
@ -322,6 +367,14 @@ public class LaunchSpecification {
return userData;
}
/**
* The IAM Instance Profile (IIP) associated with the instance.
*/
@SinceApiVersion("2012-06-01")
public Optional<IAMInstanceProfileRequest> getIAMInstanceProfile() {
return iamInstanceProfile;
}
@Override
public int hashCode() {
final int prime = 31;
@ -338,6 +391,7 @@ public class LaunchSpecification {
result = prime * result + ((securityGroupIdToNames == null) ? 0 : securityGroupIdToNames.hashCode());
result = prime * result + ((securityGroupIds == null) ? 0 : securityGroupIds.hashCode());
result = prime * result + ((securityGroupNames == null) ? 0 : securityGroupNames.hashCode());
result = prime * result + ((!iamInstanceProfile.isPresent()) ? 0 : iamInstanceProfile.get().hashCode());
result = prime * result + Arrays.hashCode(userData);
return result;
}
@ -411,6 +465,11 @@ public class LaunchSpecification {
return false;
} else if (!securityGroupNames.equals(other.securityGroupNames))
return false;
if (!iamInstanceProfile.isPresent()) {
if (other.iamInstanceProfile.isPresent())
return false;
} else if (!iamInstanceProfile.get().equals(other.iamInstanceProfile.orNull()))
return false;
if (!Arrays.equals(userData, other.userData))
return false;
return true;
@ -426,7 +485,65 @@ public class LaunchSpecification {
+ ramdiskId + ", availabilityZone=" + availabilityZone + ", subnetId=" + subnetId + ", keyName=" + keyName
+ ", securityGroupIdToNames=" + securityGroupIdToNames + ", blockDeviceMappings=" + blockDeviceMappings
+ ", securityGroupIds=" + securityGroupIds + ", securityGroupNames=" + securityGroupNames
+ ", monitoringEnabled=" + monitoringEnabled + ", userData=" + Arrays.toString(userData) + "]";
+ ", monitoringEnabled=" + monitoringEnabled + ", userData=" + Arrays.toString(userData)
+ ", iamInstanceProfile=" + iamInstanceProfile.orNull() + "]";
}
@SinceApiVersion("2012-06-01")
public static class IAMInstanceProfileRequest {
public static IAMInstanceProfileRequest forArn(String arn) {
return new IAMInstanceProfileRequest(Optional.of(checkNotNull(arn, "arn")), Optional.<String> absent());
}
public static IAMInstanceProfileRequest forName(String name) {
return new IAMInstanceProfileRequest(Optional.<String> absent(), Optional.of(checkNotNull(name, "name")));
}
public static IAMInstanceProfileRequest forArnAndName(String arn, String name) {
return new IAMInstanceProfileRequest(Optional.of(checkNotNull(arn, "arn")), Optional.of(checkNotNull(name, "name")));
}
private final Optional<String> arn;
private final Optional<String> name;
private IAMInstanceProfileRequest(Optional<String> arn, Optional<String> name) {
this.arn = checkNotNull(arn, "arn");
this.name = checkNotNull(name, "name for %s", arn);
}
/**
* The Amazon resource name (ARN) of the IAM Instance Profile (IIP) to associate with the instance.
*/
public Optional<String> getArn() {
return arn;
}
/**
* The name of the IAM Instance Profile (IIP) to associate with the instance.
*/
public Optional<String> getName() {
return name;
}
@Override
public int hashCode() {
return Objects.hashCode(arn, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
IAMInstanceProfileRequest that = IAMInstanceProfileRequest.class.cast(obj);
return equal(this.arn, that.arn) && equal(this.name, that.name);
}
@Override
public String toString() {
return toStringHelper("").omitNullValues().add("arn", arn.orNull()).add("name", name.orNull()).toString();
}
}
}

View File

@ -24,7 +24,9 @@ import java.util.Set;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.rest.annotations.SinceApiVersion;
import com.google.common.collect.ImmutableSet;
@ -93,7 +95,29 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
public AWSRunInstancesOptions withSecurityGroupIds(String... securityGroupIds) {
return withSecurityGroupIds(ImmutableSet.copyOf(securityGroupIds));
}
/**
* Amazon resource name (ARN) of the IAM Instance Profile (IIP) to associate with the instances.
*
* @see org.jclouds.aws.ec2.domain.AWSRunningInstance#getIAMInstanceProfile()
*/
@SinceApiVersion("2012-06-01")
public AWSRunInstancesOptions withIAMInstanceProfileArn(String arn) {
formParameters.put("IamInstanceProfile.Arn", checkNotNull(arn, "arn"));
return this;
}
/**
* The name of the IAM Instance Profile (IIP) to associate with the instances.
*
* @see org.jclouds.aws.ec2.domain.AWSRunningInstance#getIAMInstanceProfile()
*/
@SinceApiVersion("2012-06-01")
public AWSRunInstancesOptions withIAMInstanceProfileName(String name) {
formParameters.put("IamInstanceProfile.Name", checkNotNull(name, "name"));
return this;
}
public static class Builder extends RunInstancesOptions.Builder {
/**
@ -128,6 +152,22 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
return options.withSubnetId(subnetId);
}
/**
* @see AWSRunInstancesOptions#withIAMInstanceProfileArn(String)
*/
public static AWSRunInstancesOptions withIAMInstanceProfileArn(String arn) {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
return options.withIAMInstanceProfileArn(arn);
}
/**
* @see AWSRunInstancesOptions#withIAMInstanceProfileName(String)
*/
public static AWSRunInstancesOptions withIAMInstanceProfileName(String id) {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
return options.withIAMInstanceProfileName(id);
}
/**
* @see AWSRunInstancesOptions#withKeyName(String)
*/

View File

@ -95,6 +95,7 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
private Set<RunningInstance> instances = Sets.newLinkedHashSet();
private boolean inPlacement;
private boolean inIamInstanceProfile;
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
@ -104,6 +105,8 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
inInstancesSet = true;
} else if (equalsOrSuffix(qName, "placement")) {
inPlacement = true;
} else if (equalsOrSuffix(qName, "iamInstanceProfile")) {
inIamInstanceProfile = true;
}
}
@ -117,6 +120,10 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
groupId = currentOrNull(currentText);
} else if (equalsOrSuffix(qName, "groupName") && inPlacement) {
builder.placementGroup(currentOrNull(currentText));
} else if (equalsOrSuffix(qName, "arn") && inIamInstanceProfile) {
builder.iamInstanceProfileArn(currentOrNull(currentText));
} else if (equalsOrSuffix(qName, "id") && inIamInstanceProfile) {
builder.iamInstanceProfileId(currentOrNull(currentText));
} else if (equalsOrSuffix(qName, "groupName")) {
switch (itemDepth) {
case 2:
@ -141,6 +148,8 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
inInstancesSet = false;
} else if (equalsOrSuffix(qName, "placement")) {
inPlacement = false;
} else if (equalsOrSuffix(qName, "iamInstanceProfile")) {
inIamInstanceProfile = false;
} else if (equalsOrSuffix(qName, "ownerId")) {
ownerId = currentOrNull(currentText);
} else if (equalsOrSuffix(qName, "requesterId")) {

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.aws.ec2.xml;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import javax.annotation.Resource;
import javax.inject.Inject;
@ -59,24 +61,33 @@ public class LaunchSpecificationHandler extends HandlerForGeneratedRequestWithRe
protected StringBuilder currentText = new StringBuilder();
private boolean inBlockDeviceMapping;
private boolean inIamInstanceProfile;
private String groupId;
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = true;
} else if (equalsOrSuffix(qName, "iamInstanceProfile")) {
inIamInstanceProfile = true;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = false;
} else if (equalsOrSuffix(qName, "iamInstanceProfile")) {
inIamInstanceProfile = false;
} else if (qName.equals("item") && inBlockDeviceMapping) {
try {
builder.blockDeviceMapping(blockDeviceMappingBuilder.build());
} finally {
blockDeviceMappingBuilder.clear();
}
} else if (equalsOrSuffix(qName, "arn") && inIamInstanceProfile) {
builder.iamInstanceProfileArn(currentOrNull());
} else if (equalsOrSuffix(qName, "name") && inIamInstanceProfile) {
builder.iamInstanceProfileName(currentOrNull());
} else if (qName.equals("deviceName")) {
blockDeviceMappingBuilder.deviceName(currentOrNull());
} else if (qName.equals("virtualName")) {

View File

@ -75,4 +75,26 @@ public class BindLaunchSpecificationToFormParamsTest {
assertEquals(binder.apply(spec), ImmutableMap.of("LaunchSpecification.InstanceType", "t1.micro",
"LaunchSpecification.ImageId", "ami-123", "LaunchSpecification.SubnetId", "subnet-xyz"));
}
@Test
public void testApplyWithIAMInstanceProfileArn() {
LaunchSpecification spec = LaunchSpecification.builder()
.instanceType(InstanceType.T1_MICRO)
.imageId("ami-123")
.iamInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver")
.build();
assertEquals(binder.apply(spec), ImmutableMap.of("LaunchSpecification.InstanceType", "t1.micro",
"LaunchSpecification.ImageId", "ami-123", "LaunchSpecification.IamInstanceProfile.Arn",
"arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver"));
}
@Test
public void testApplyWithIAMInstanceProfileName() {
LaunchSpecification spec = LaunchSpecification.builder().instanceType(InstanceType.T1_MICRO).imageId("ami-123")
.iamInstanceProfileName("Webserver").build();
assertEquals(binder.apply(spec), ImmutableMap.of("LaunchSpecification.InstanceType", "t1.micro",
"LaunchSpecification.ImageId", "ami-123", "LaunchSpecification.IamInstanceProfile.Name", "Webserver"));
}
}

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.aws.ec2.compute;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.blockUntilRunning;
import static org.testng.Assert.assertEquals;
import javax.ws.rs.core.MediaType;
@ -29,6 +30,7 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
@ -43,7 +45,30 @@ import com.google.common.collect.Iterables;
@Test(groups = "unit", testName = "AWSEC2ComputeServiceExpectTest")
public class AWSEC2ComputeServiceExpectTest extends BaseAWSEC2ComputeServiceExpectTest {
public void testLaunchVPCSpotInstanceMissesVPCId() throws Exception {
private HttpResponse requestSpotInstancesResponse;
private HttpRequest describeSpotInstanceRequest;
private HttpResponse describeSpotInstanceResponse;
@BeforeClass
@Override
protected void setupDefaultRequests() {
super.setupDefaultRequests();
requestSpotInstancesResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType(
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
describeSpotInstanceRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "DescribeSpotInstanceRequests")
.addFormParam("SpotInstanceRequestId.1", "sir-228e6406").build());
describeSpotInstanceResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType(
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
}
public void testLaunchVPCSpotInstanceSubnetId() throws Exception {
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
@ -56,20 +81,6 @@ public class AWSEC2ComputeServiceExpectTest extends BaseAWSEC2ComputeServiceExpe
.addFormParam("LaunchSpecification.SubnetId", "subnet-xyz")
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
.addFormParam("SpotPrice", "1.0").build());
HttpResponse requestSpotInstancesResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType(
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
HttpRequest describeSpotInstanceRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "DescribeSpotInstanceRequests")
.addFormParam("SpotInstanceRequestId.1", "sir-228e6406").build());
HttpResponse describeSpotInstanceResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType(
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
@ -89,10 +100,152 @@ public class AWSEC2ComputeServiceExpectTest extends BaseAWSEC2ComputeServiceExpe
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).subnetId("subnet-xyz").keyPair("Demo").blockUntilRunning(false);
NodeMetadata node = Iterables.getOnlyElement(createsVPCSpotInstance.createNodesInGroup("demoGroup", 1, template));
NodeMetadata node = Iterables.getOnlyElement(createsVPCSpotInstance.createNodesInGroup("test", 1, template));
assertEquals(node.getId(), "us-east-1/sir-228e6406");
}
String iamInstanceProfileArn = "arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver";
public void testLaunchSpotInstanceIAMInstanceProfileArn() throws Exception {
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "RequestSpotInstances")
.addFormParam("InstanceCount", "1")
.addFormParam("LaunchSpecification.IamInstanceProfile.Arn", iamInstanceProfileArn)
.addFormParam("LaunchSpecification.ImageId", "ami-be3adfd7")
.addFormParam("LaunchSpecification.InstanceType", "m1.small")
.addFormParam("LaunchSpecification.Placement.AvailabilityZone", "us-east-1a")
.addFormParam("LaunchSpecification.SecurityGroup.1", "jclouds#test")
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
.addFormParam("SpotPrice", "1.0").build());
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(requestSpotInstancesRequest, requestSpotInstancesResponse);
requestResponseMap.put(describeSpotInstanceRequest, describeSpotInstanceResponse);
ComputeService createsSpotInstance = requestsSendResponses(requestResponseMap.build());
Template template = createsSpotInstance.templateBuilder().locationId("us-east-1a").build();
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileArn(iamInstanceProfileArn)
.noKeyPair().blockUntilRunning(false);
NodeMetadata node = Iterables.getOnlyElement(createsSpotInstance.createNodesInGroup("test", 1, template));
assertEquals(node.getId(), "us-east-1/sir-228e6406");
}
public void testLaunchSpotInstanceIAMInstanceProfileName() throws Exception {
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "RequestSpotInstances")
.addFormParam("InstanceCount", "1")
.addFormParam("LaunchSpecification.IamInstanceProfile.Name", "Webserver")
.addFormParam("LaunchSpecification.ImageId", "ami-be3adfd7")
.addFormParam("LaunchSpecification.InstanceType", "m1.small")
.addFormParam("LaunchSpecification.Placement.AvailabilityZone", "us-east-1a")
.addFormParam("LaunchSpecification.SecurityGroup.1", "jclouds#test")
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
.addFormParam("SpotPrice", "1.0").build());
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(requestSpotInstancesRequest, requestSpotInstancesResponse);
requestResponseMap.put(describeSpotInstanceRequest, describeSpotInstanceResponse);
ComputeService createsSpotInstance = requestsSendResponses(requestResponseMap.build());
Template template = createsSpotInstance.templateBuilder().locationId("us-east-1a").build();
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileName("Webserver")
.noKeyPair().blockUntilRunning(false);
NodeMetadata node = Iterables.getOnlyElement(createsSpotInstance.createNodesInGroup("test", 1, template));
assertEquals(node.getId(), "us-east-1/sir-228e6406");
}
public void testCreateNodeWithIAMInstanceProfileArn() throws Exception {
HttpRequest runInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "RunInstances")
.addFormParam("IamInstanceProfile.Arn", iamInstanceProfileArn)
.addFormParam("ImageId", "ami-be3adfd7")
.addFormParam("InstanceType", "m1.small")
.addFormParam("MaxCount", "1")
.addFormParam("MinCount", "1")
.addFormParam("SecurityGroup.1", "jclouds#test")
.addFormParam("UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK").build());
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(runInstancesRequest, runInstancesResponse);
requestResponseMap.put(describeInstanceRequest, describeInstanceResponse);
requestResponseMap.put(describeImageRequest, describeImagesResponse);
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
blockUntilRunning(false).iamInstanceProfileArn(iamInstanceProfileArn).noKeyPair()));
assertEquals(node.getId(), "us-east-1/i-2baa5550");
}
public void testCreateNodeWithIAMInstanceProfileName() throws Exception {
HttpRequest runInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "RunInstances")
.addFormParam("IamInstanceProfile.Name", "Webserver")
.addFormParam("ImageId", "ami-be3adfd7")
.addFormParam("InstanceType", "m1.small")
.addFormParam("MaxCount", "1")
.addFormParam("MinCount", "1")
.addFormParam("SecurityGroup.1", "jclouds#test")
.addFormParam("UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK").build());
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
requestResponseMap.put(runInstancesRequest, runInstancesResponse);
requestResponseMap.put(describeInstanceRequest, describeInstanceResponse);
requestResponseMap.put(describeImageRequest, describeImagesResponse);
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
blockUntilRunning(false).iamInstanceProfileName("Webserver").noKeyPair()));
assertEquals(node.getId(), "us-east-1/i-2baa5550");
}
public void testListNodesWhereImageDoesntExist() throws Exception {
HttpRequest describeInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")

View File

@ -20,6 +20,7 @@ package org.jclouds.aws.ec2.compute;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.collect.Sets.newTreeSet;
import static java.util.logging.Logger.getAnonymousLogger;
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
import static org.jclouds.ec2.util.IpPermissions.permit;
@ -36,6 +37,7 @@ import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.MonitoringState;
import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
import org.jclouds.aws.iam.AWSIAMProviderMetadata;
import org.jclouds.cloudwatch.CloudWatchApi;
import org.jclouds.cloudwatch.CloudWatchAsyncApi;
import org.jclouds.cloudwatch.domain.Dimension;
@ -56,6 +58,9 @@ import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.SecurityGroup;
import org.jclouds.ec2.services.InstanceClient;
import org.jclouds.ec2.services.KeyPairClient;
import org.jclouds.iam.IAMApi;
import org.jclouds.iam.IAMAsyncApi;
import org.jclouds.iam.domain.InstanceProfile;
import org.jclouds.rest.RestContext;
import org.jclouds.scriptbuilder.domain.Statements;
import org.testng.annotations.Test;
@ -82,6 +87,13 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
public void testExtendedOptionsAndLogin() throws Exception {
String region = "us-west-2";
RestContext<IAMApi, IAMAsyncApi> iamContext = ContextBuilder.newBuilder(new AWSIAMProviderMetadata())
.credentials(identity, credential)
.modules(setupModules()).build();
String profileName = "ec2Test";
// Note this needs to wait an undefined amount of time before it is visible to ec2, seems to be about 15seconds
InstanceProfile profile = createIAMInstanceProfile(iamContext.getApi(), profileName);
AWSSecurityGroupClient securityGroupClient = AWSEC2Client.class.cast(
view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi()).getSecurityGroupServices();
@ -106,6 +118,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
template.getOptions().tags(tags);
template.getOptions().as(AWSEC2TemplateOptions.class).enableMonitoring();
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
template.getOptions().as(AWSEC2TemplateOptions.class).iamInstanceProfileName(profileName);
String startedId = null;
try {
@ -146,6 +159,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
assertEquals(instance.getKeyName(), group);
assert instance.getSpotInstanceRequestId() != null;
assertEquals(instance.getMonitoringState(), MonitoringState.ENABLED);
assertEquals(instance.getIAMInstanceProfile().get().getArn(), profile.getArn());
// generate some load
ListenableFuture<ExecResponse> future = client.submitScriptOnNode(first.getId(), Statements
@ -199,9 +213,31 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
assertEquals(keyPairClient.describeKeyPairsInRegion(region, group).size(), 1);
assertEquals(securityGroupClient.describeSecurityGroupsInRegion(region, group).size(), 1);
}
deleteIAMInstanceProfile(iamContext.getApi(), profileName);
iamContext.close();
cleanupExtendedStuffInRegion(region, securityGroupClient, keyPairClient, group);
}
}
static String assumeRolePolicy = "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}";
static String route53Policy = "{\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"route53:*\",\"Resource\":\"*\"}]}";
static InstanceProfile createIAMInstanceProfile(IAMApi api, String name) {
String roleName = name + "route53";
api.getRoleApi().createWithPolicy(roleName, assumeRolePolicy);
api.getPolicyApiForRole(roleName).create("route53-readonly", route53Policy);
api.getInstanceProfileApi().create(name);
api.getInstanceProfileApi().addRole(name, roleName);
InstanceProfile updated = api.getInstanceProfileApi().get(name);
getAnonymousLogger().info("created instanceProfile: " + updated);
return updated;
}
static void deleteIAMInstanceProfile(IAMApi api, String name) {
String roleName = name + "route53";
api.getInstanceProfileApi().removeRole(name, roleName);
api.getPolicyApiForRole(roleName).delete("route53-readonly");
api.getRoleApi().delete(roleName);
api.getInstanceProfileApi().delete(name);
}
}

View File

@ -21,6 +21,8 @@ package org.jclouds.aws.ec2.compute.options;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.authorizePublicKey;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.blockOnPort;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.enableMonitoring;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.iamInstanceProfileArn;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.iamInstanceProfileName;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.inboundPorts;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.installPrivateKey;
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.keyPair;
@ -367,4 +369,52 @@ public class AWSEC2TemplateOptionsTest {
assertEquals(options.getInboundPorts()[0], 22);
assertEquals(options.getInboundPorts()[1], 30);
}
@Test
public void testIAMInstanceProfileArn() {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
options.iamInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
assertEquals(options.getIAMInstanceProfileArn(), "arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
}
@Test
public void testNullIAMInstanceProfileArn() {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
assertEquals(options.getIAMInstanceProfileArn(), null);
}
@Test
public void testIAMInstanceProfileArnStatic() {
AWSEC2TemplateOptions options = iamInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
assertEquals(options.getIAMInstanceProfileArn(), "arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
}
@Test(expectedExceptions = NullPointerException.class)
public void testIAMInstanceProfileArnNPE() {
iamInstanceProfileArn(null);
}
@Test
public void testIAMInstanceProfileName() {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
options.iamInstanceProfileName("Webserver");
assertEquals(options.getIAMInstanceProfileName(), "Webserver");
}
@Test
public void testNullIAMInstanceProfileName() {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
assertEquals(options.getIAMInstanceProfileName(), null);
}
@Test
public void testIAMInstanceProfileNameStatic() {
AWSEC2TemplateOptions options = iamInstanceProfileName("Webserver");
assertEquals(options.getIAMInstanceProfileName(), "Webserver");
}
@Test(expectedExceptions = NullPointerException.class)
public void testIAMInstanceProfileNameNPE() {
iamInstanceProfileName(null);
}
}

View File

@ -21,6 +21,8 @@ package org.jclouds.aws.ec2.options;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.asType;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.enableMonitoring;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withBlockDeviceMappings;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withIAMInstanceProfileArn;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withIAMInstanceProfileName;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withKernelId;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withKeyName;
import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withRamdisk;
@ -250,6 +252,57 @@ public class AWSRunInstancesOptionsTest {
withSubnetId(null);
}
@Test
public void testWithIAMInstanceProfileArn() {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
options
.withIAMInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Arn"),
ImmutableList.of("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver"));
}
@Test
public void testNullWithIAMInstanceProfileArn() {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Arn"), ImmutableList.of());
}
@Test
public void testWithIAMInstanceProfileArnStatic() {
AWSRunInstancesOptions options = withIAMInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Arn"),
ImmutableList.of("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithIAMInstanceProfileArnNPE() {
withIAMInstanceProfileArn(null);
}
@Test
public void testWithIAMInstanceProfileName() {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
options.withIAMInstanceProfileName("Webserver");
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Name"), ImmutableList.of("Webserver"));
}
@Test
public void testNullWithIAMInstanceProfileName() {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Name"), ImmutableList.of());
}
@Test
public void testWithIAMInstanceProfileNameStatic() {
AWSRunInstancesOptions options = withIAMInstanceProfileName("Webserver");
assertEquals(options.buildFormParameters().get("IamInstanceProfile.Name"), ImmutableList.of("Webserver"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithIAMInstanceProfileNameNPE() {
withIAMInstanceProfileName(null);
}
@Test
public void testWithRamdisk() {
AWSRunInstancesOptions options = new AWSRunInstancesOptions();

View File

@ -130,7 +130,10 @@ public class AWSDescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest
new BlockDevice("vol-5029fc3a", Attachment.Status.ATTACHED, dateService
.iso8601DateParse("2011-08-16T13:41:19.000Z"), true))
.hypervisor(Hypervisor.XEN)
.virtualizationType("paravirtual").build()).build());
.virtualizationType("paravirtual")
.iamInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver")
.iamInstanceProfileId("AIPAD5ARO2C5EXAMPLE3G")
.build()).build());
Set<Reservation<? extends RunningInstance>> result = parseAWSRunningInstances("/describe_instances_latest.xml");

View File

@ -85,7 +85,9 @@ public class SpotInstanceHandlerTest extends BaseEC2HandlerTest {
LaunchSpecification.builder().imageId("ami-595a0a1c").securityGroupIdToName("sg-83e1c4ea", "default")
.instanceType("m1.large").mapNewVolumeToDevice("/dev/sda1", 1, true)
.mapEBSSnapshotToDevice("/dev/sda2", "snap-1ea27576", 1, true)
.mapEphemeralDeviceToDevice("/dev/sda3", "vre1").monitoringEnabled(false).build())
.mapEphemeralDeviceToDevice("/dev/sda3", "vre1").monitoringEnabled(false)
.iamInstanceProfileArn("arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver")
.iamInstanceProfileName("Webserver").build())
.createTime(new SimpleDateFormatDateService().iso8601DateParse("2011-03-08T03:30:36.000Z"))
.productDescription("Linux/UNIX").build();
SpotInstanceHandler handler = injector.getInstance(SpotInstanceHandler.class);
@ -94,7 +96,9 @@ public class SpotInstanceHandlerTest extends BaseEC2HandlerTest {
assertEquals(result.toString(), expected.toString());
assertEquals(result.getState(), State.OPEN);
assertEquals(result.getRawState(), "open");
assertEquals(result.getLaunchSpecification().getIAMInstanceProfile().get().getArn().get(),
"arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver");
assertEquals(result.getLaunchSpecification().getIAMInstanceProfile().get().getName().get(), "Webserver");
}
public void testApplyInputStream1() {

View File

@ -1,4 +1,4 @@
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>b3e1c7ee-1f34-4582-9493-695c9425c679</requestId>
<reservationSet>
<item>

View File

@ -1,4 +1,4 @@
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>b2238f71-750f-4eed-8f5c-eb4e6f66b687</requestId>
<reservationSet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>440faed2-0331-488d-a04d-d8c9aba85307</requestId>
<reservationSet/>
</DescribeInstancesResponse>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>a03c1896-0543-485f-a732-ebc83873a3ca</requestId>
<reservationSet>
<item>
@ -70,7 +70,7 @@
<key>Empty</key>
<value />
</item>
</tagSet>
</tagSet>
</item>
<item>
<instanceId>i-931444f2</instanceId>
@ -121,6 +121,10 @@
<virtualizationType>paravirtual</virtualizationType>
<clientToken/>
<hypervisor>xen</hypervisor>
<iamInstanceProfile>
<arn>arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver</arn>
<id>AIPAD5ARO2C5EXAMPLE3G</id>
</iamInstanceProfile>
</item>
</instancesSet>
</item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>dcd37ecf-e5b6-462b-99a8-112427b3e3a2</requestId>
<reservationSet>
<item>

View File

@ -1,4 +1,4 @@
<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>xxxxxxxxxxxxxxxx</requestId>
<securityGroupInfo>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>d9da716a-5cd4-492e-83b9-6777ac16d6cf</requestId>
<spotInstanceRequestSet>
<item>

View File

@ -1,4 +1,4 @@
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>7c4dd2bd-106d-4cd3-987c-35ee819180a6</requestId>
<spotInstanceRequestSet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>f2247378-7df0-4725-b55f-8ef58b557dcd</requestId>
<spotInstanceRequestSet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>f2247378-7df0-4725-b55f-8ef58b557dcd</requestId>
<spotInstanceRequestSet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSpotPriceHistoryResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<DescribeSpotPriceHistoryResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>99777a75-2a2b-4296-a305-650c442d2d63</requestId>
<spotPriceHistorySet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>02401e8e-a4f5-4285-8ea8-6d742fbaadd8</requestId>
<spotInstanceRequestSet>
<item>
@ -40,6 +40,10 @@
<monitoring>
<enabled>false</enabled>
</monitoring>
<iamInstanceProfile>
<arn>arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver</arn>
<name>Webserver</name>
</iamInstanceProfile>
</launchSpecification>
<createTime>2011-03-08T03:30:36.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>2ffc645f-6835-4d23-bd18-f6f53c253067</requestId>
<spotInstanceRequestSet>
<item>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2012-06-01/">
<requestId>7faf9500-67ef-484b-9fa5-73b6df638bc8</requestId>
<reservationId>r-d3b815bc</reservationId>
<ownerId>993194456877</ownerId>