Skip to content

Commit

Permalink
Merge pull request #52 from ww-mgr/ec2-iamrole
Browse files Browse the repository at this point in the history
JENKINS-17086 Add iamRole option to slave configuration
  • Loading branch information
francisu committed May 16, 2013
2 parents 3ee74a4 + b5f2eb7 commit 4102f1c
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 16 deletions.
46 changes: 35 additions & 11 deletions src/main/java/hudson/plugins/ec2/SlaveTemplate.java
Expand Up @@ -75,6 +75,7 @@ public class SlaveTemplate implements Describable<SlaveTemplate> {
public final String jvmopts;
public final String subnetId;
public final String idleTerminationMinutes;
public final String iamInstanceProfile;
public int instanceCap;
public final boolean stopOnTerminate;
private final List<EC2Tag> tags;
Expand All @@ -86,7 +87,7 @@ public class SlaveTemplate implements Describable<SlaveTemplate> {
private transient /*almost final*/ Set<String> securityGroupSet;

@DataBoundConstructor
public SlaveTemplate(String ami, String zone, SpotConfiguration spotConfig, String securityGroups, String remoteFS, String sshPort, InstanceType type, String labelString, Node.Mode mode, String description, String initScript, String userData, String numExecutors, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String subnetId, List<EC2Tag> tags, String idleTerminationMinutes, boolean usePrivateDnsName, String instanceCapStr) {
public SlaveTemplate(String ami, String zone, SpotConfiguration spotConfig, String securityGroups, String remoteFS, String sshPort, InstanceType type, String labelString, Node.Mode mode, String description, String initScript, String userData, String numExecutors, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String subnetId, List<EC2Tag> tags, String idleTerminationMinutes, boolean usePrivateDnsName, String instanceCapStr, String iamInstanceProfile) {
this.ami = ami;
this.zone = zone;
this.spotConfig = spotConfig;
Expand Down Expand Up @@ -114,7 +115,9 @@ public SlaveTemplate(String ami, String zone, SpotConfiguration spotConfig, Stri
} else {
this.instanceCap = Integer.parseInt(instanceCapStr);
}


this.iamInstanceProfile = iamInstanceProfile;

readResolve(); // initialize
}

Expand Down Expand Up @@ -218,6 +221,10 @@ public String getSpotMaxBidPrice(){
return null;
return SpotConfiguration.normalizeBid(spotConfig.spotMaxBidPrice);
}

public String getIamInstanceProfile() {
return iamInstanceProfile;
}


/**
Expand Down Expand Up @@ -292,7 +299,7 @@ private EC2AbstractSlave provisionOndemand(TaskListener listener) throws AmazonC
diFilters.add(new Filter("key-name").withValues(keyPair.getKeyName()));
riRequest.setInstanceType(type.toString());
diFilters.add(new Filter("instance-type").withValues(type.toString()));

HashSet<Tag> inst_tags = null;
if (tags != null && !tags.isEmpty()) {
inst_tags = new HashSet<Tag>();
Expand All @@ -309,7 +316,25 @@ private EC2AbstractSlave provisionOndemand(TaskListener listener) throws AmazonC
logger.println("Looking for existing instances: "+diRequest);

DescribeInstancesResult diResult = ec2.describeInstances(diRequest);
if (diResult.getReservations().size() == 0) {

Instance existingInstance = null;
if (StringUtils.isNotBlank(getIamInstanceProfile())) {
riRequest.setIamInstanceProfile(new IamInstanceProfileSpecification().withArn(getIamInstanceProfile()));
// cannot filter on IAM Instance Profile, so search in result
reservationLoop:
for (Reservation reservation : diResult.getReservations()) {
for (Instance instance : reservation.getInstances()) {
if (instance.getIamInstanceProfile() != null && instance.getIamInstanceProfile().getArn().equals(getIamInstanceProfile())) {
existingInstance = instance;
break reservationLoop;
}
}
}
} else if (diResult.getReservations().size() > 0) {
existingInstance = diResult.getReservations().get(0).getInstances().get(0);
}

if (existingInstance == null) {
// Have to create a new instance
Instance inst = ec2.runInstances(riRequest).getReservation().getInstances().get(0);

Expand All @@ -324,28 +349,27 @@ private EC2AbstractSlave provisionOndemand(TaskListener listener) throws AmazonC
return newOndemandSlave(inst);
}

Instance inst = diResult.getReservations().get(0).getInstances().get(0);
logger.println("Found existing stopped instance: "+inst);
logger.println("Found existing stopped instance: "+existingInstance);
List<String> instances = new ArrayList<String>();
instances.add(inst.getInstanceId());
instances.add(existingInstance.getInstanceId());
StartInstancesRequest siRequest = new StartInstancesRequest(instances);
StartInstancesResult siResult = ec2.startInstances(siRequest);
logger.println("Starting existing instance: "+inst+ " result:"+siResult);
logger.println("Starting existing instance: "+existingInstance+ " result:"+siResult);

List<Node> nodes = Hudson.getInstance().getNodes();
for (int i = 0, len = nodes.size(); i < len; i++) {
if (!(nodes.get(i) instanceof EC2AbstractSlave))
continue;
EC2AbstractSlave ec2Node = (EC2AbstractSlave) nodes.get(i);
if (ec2Node.getInstanceId().equals(inst.getInstanceId())) {
if (ec2Node.getInstanceId().equals(existingInstance.getInstanceId())) {
logger.println("Found existing corresponding: "+ec2Node);
return ec2Node;
}
}

// Existing slave not found
logger.println("Creating new slave for existing instance: "+inst);
return newOndemandSlave(inst);
logger.println("Creating new slave for existing instance: "+existingInstance);
return newOndemandSlave(existingInstance);

} catch (FormException e) {
throw new AssertionError(); // we should have discovered all configuration issues upfront
Expand Down
Expand Up @@ -133,6 +133,10 @@ THE SOFTWARE.
<f:entry title="${%Instance Cap}" field="instanceCapStr">
<f:textbox />
</f:entry>

<f:entry title="${%IAM Instance Profile}" field="iamInstanceProfile">
<f:textbox />
</f:entry>
</f:advanced>

<f:entry title="">
Expand Down
@@ -0,0 +1,7 @@
<div>
<p>IAM Instance Profile ARN e.g. arn:aws:iam::000000000000:instance-profile/SampleName.</p>
<p>An instance profile is a container for a role.
To associate a role to an Amazon EC2 instance, you must use the instance profile ARN.
Roles enable you to manage permissions for applications running on EC2.</p>
<p>The Instance Profile ARN can be found in the IAM Role's <b>Summary</b> tab in the AWS Management Console.</p>
</div>
34 changes: 31 additions & 3 deletions src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java
Expand Up @@ -59,7 +59,7 @@ public void testConfigRoundtrip() throws Exception {
tags.add( tag1 );
tags.add( tag2 );

SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, false, null);
SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, false, null, "");

List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(orig);
Expand All @@ -82,7 +82,7 @@ public void testConfigRoundtripWithPrivateDns() throws Exception {
tags.add( tag1 );
tags.add( tag2 );

SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, true, null);
SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, true, null, "");

List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(orig);
Expand Down Expand Up @@ -112,7 +112,7 @@ public void testConfigWithSpotBidPrice() throws Exception {

SpotConfiguration spotConfig = new SpotConfiguration(".05", SpotInstanceType.OneTime.toString());

SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, spotConfig, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, true, null);
SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, spotConfig, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, true, null, "");
List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(orig);

Expand All @@ -124,4 +124,32 @@ public void testConfigWithSpotBidPrice() throws Exception {
assertEqualBeans(orig, received, "ami,zone,spotConfig,description,remoteFS,type,jvmopts,stopOnTerminate,securityGroups,subnetId,tags,usePrivateDnsName");
}

/**
* Test to make sure the IAM Role is set properly.
*
* @throws Exception
*/
public void testConfigRoundtripIamRole() throws Exception {
String ami = "ami1";
String description = "foo ami";

EC2Tag tag1 = new EC2Tag( "name1", "value1" );
EC2Tag tag2 = new EC2Tag( "name2", "value2" );
List<EC2Tag> tags = new ArrayList<EC2Tag>();
tags.add( tag1 );
tags.add( tag2 );

SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", "22", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false, "subnet 456", tags, null, false, null, "iamInstanceProfile");

List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(orig);

AmazonEC2Cloud ac = new AmazonEC2Cloud("abc", "def", "us-east-1", "ghi", "3", templates);
hudson.clouds.add(ac);

submit(createWebClient().goTo("configure").getFormByName("config"));
SlaveTemplate received = ((EC2Cloud)hudson.clouds.iterator().next()).getTemplate(description);
assertEqualBeans(orig, received, "ami,zone,description,remoteFS,type,jvmopts,stopOnTerminate,securityGroups,subnetId,usePrivateDnsName,iamInstanceProfile");
}

}
4 changes: 2 additions & 2 deletions src/test/java/hudson/plugins/ec2/TemplateLabelsTest.java
Expand Up @@ -50,7 +50,7 @@ public void setUp() throws Exception{
tags.add( tag1 );
tags.add( tag2 );

SlaveTemplate template = new SlaveTemplate("ami", "foo", null, "default", "zone", "22", InstanceType.M1Large, LABEL1 + " " + LABEL2, Node.Mode.NORMAL,"foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true, "subnet 456", tags, null, false, null);
SlaveTemplate template = new SlaveTemplate("ami", "foo", null, "default", "zone", "22", InstanceType.M1Large, LABEL1 + " " + LABEL2, Node.Mode.NORMAL,"foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true, "subnet 456", tags, null, false, null, "");
List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(template);

Expand Down Expand Up @@ -79,7 +79,7 @@ public void testEmptyLabel() throws Exception{
tags.add( tag1 );
tags.add( tag2 );

SlaveTemplate temp = new SlaveTemplate("ami", "foo", null, "default", "zone", "22", InstanceType.M1Large, "", Node.Mode.NORMAL, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true, "subnet 456", tags, null, false, null);
SlaveTemplate temp = new SlaveTemplate("ami", "foo", null, "default", "zone", "22", InstanceType.M1Large, "", Node.Mode.NORMAL, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true, "subnet 456", tags, null, false, null, "");
List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(temp);

Expand Down

0 comments on commit 4102f1c

Please sign in to comment.