Skip to content
Permalink
Browse files
[FIXED JENKINS-12772] Allow instances to be stopped (instead of termi…
…nated) when they are not required
  • Loading branch information
francisu committed Feb 23, 2012
1 parent 9e89c6c commit a2739cd93cfdf518dfff795e16da9e121a5bdcd1
Showing 6 changed files with 36 additions and 13 deletions.
@@ -27,6 +27,7 @@
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult;
import com.amazonaws.services.ec2.model.InstanceType;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;

/**
@@ -42,6 +43,7 @@ public final class EC2Slave extends Slave {
public final String remoteAdmin; // e.g. 'ubuntu'
public final String rootCommandPrefix; // e.g. 'sudo'
public final String jvmopts; //e.g. -Xmx1g
public final boolean stopOnTerminate;

/**
* For data read from old Hudson, this is 0, so we use that to indicate 22.
@@ -50,25 +52,26 @@ public final class EC2Slave extends Slave {

public static final String TEST_ZONE = "testZone";

public EC2Slave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, String labelString, String initScript, String remoteAdmin, String rootCommandPrefix, String jvmopts) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, Mode.NORMAL, labelString, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts);
public EC2Slave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, String labelString, String initScript, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, Mode.NORMAL, labelString, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate);
}

@DataBoundConstructor
public EC2Slave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, Mode mode, String labelString, String initScript, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String rootCommandPrefix, String jvmopts) throws FormException, IOException {
public EC2Slave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, Mode mode, String labelString, String initScript, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate) throws FormException, IOException {
super(instanceId, description, remoteFS, numExecutors, mode, labelString, new EC2UnixLauncher(), new EC2RetentionStrategy(), nodeProperties);
this.initScript = initScript;
this.remoteAdmin = remoteAdmin;
this.rootCommandPrefix = rootCommandPrefix;
this.jvmopts = jvmopts;
this.sshPort = sshPort;
this.stopOnTerminate = stopOnTerminate;
}

/**
* Constructor for debugging.
*/
public EC2Slave(String instanceId) throws FormException, IOException {
this(instanceId,"debug", "/tmp/hudson", 22, 1, Mode.NORMAL, "debug", "", Collections.<NodeProperty<?>>emptyList(), null, null, null);
this(instanceId,"debug", "/tmp/hudson", 22, 1, Mode.NORMAL, "debug", "", Collections.<NodeProperty<?>>emptyList(), null, null, null, false);
}

/**
@@ -109,9 +112,15 @@ public Computer createComputer() {
public void terminate() {
try {
AmazonEC2 ec2 = EC2Cloud.get().connect();
TerminateInstancesRequest request = new TerminateInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.terminateInstances(request);
LOGGER.info("Terminated EC2 instance: "+getInstanceId());
if (stopOnTerminate) {
StopInstancesRequest request = new StopInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.stopInstances(request);
LOGGER.info("Terminated EC2 instance (stopped): "+getInstanceId());
} else {
TerminateInstancesRequest request = new TerminateInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.terminateInstances(request);
LOGGER.info("Terminated EC2 instance (terminated): "+getInstanceId());
}
Hudson.getInstance().removeNode(this);
} catch (AmazonClientException e) {
LOGGER.log(Level.WARNING,"Failed to terminate EC2 instance: "+getInstanceId(),e);
@@ -140,6 +149,10 @@ public int getSshPort() {
return sshPort!=0 ? sshPort : 22;
}

public boolean getStopOnTerminate() {
return stopOnTerminate;
}

public static ListBoxModel fillZoneItems(String accessId,
String secretKey, String region) throws IOException,
ServletException {
@@ -56,12 +56,14 @@ public class SlaveTemplate implements Describable<SlaveTemplate> {
public final String remoteAdmin;
public final String rootCommandPrefix;
public final String jvmopts;
public final boolean stopOnTerminate;
protected transient EC2Cloud parent;


private transient /*almost final*/ Set<LabelAtom> labelSet;

@DataBoundConstructor
public SlaveTemplate(String ami, String zone, String remoteFS, String sshPort, InstanceType type, String labelString, String description, String initScript, String userData, String numExecutors, String remoteAdmin, String rootCommandPrefix, String jvmopts) {
public SlaveTemplate(String ami, String zone, String remoteFS, String sshPort, InstanceType type, String labelString, String description, String initScript, String userData, String numExecutors, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate) {
this.ami = ami;
this.zone = zone;
this.remoteFS = remoteFS;
@@ -75,6 +77,7 @@ public SlaveTemplate(String ami, String zone, String remoteFS, String sshPort, I
this.remoteAdmin = remoteAdmin;
this.rootCommandPrefix = rootCommandPrefix;
this.jvmopts = jvmopts;
this.stopOnTerminate = stopOnTerminate;
readResolve(); // initialize
}

@@ -161,7 +164,7 @@ public EC2Slave provision(TaskListener listener) throws AmazonClientException, I
}

private EC2Slave newSlave(Instance inst) throws FormException, IOException {
return new EC2Slave(inst.getInstanceId(), description, remoteFS, getSshPort(), getNumExecutors(), labels, initScript, remoteAdmin, rootCommandPrefix, jvmopts);
return new EC2Slave(inst.getInstanceId(), description, remoteFS, getSshPort(), getNumExecutors(), labels, initScript, remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate);
}

/**
@@ -63,6 +63,10 @@ THE SOFTWARE.
<f:textbox />
</f:entry>

<f:entry title="${%Stop on Terminate}" field="stopOnTerminate">
<f:checkbox />
</f:entry>

<f:descriptorList title="${%Node Properties}" descriptors="${h.getNodePropertyDescriptors(descriptor.clazz)}" field="nodeProperties" />

<f:block>
@@ -66,6 +66,9 @@ THE SOFTWARE.
<f:entry title="${%Remote ssh port}" field="sshPort">
<f:textbox />
</f:entry>
<f:entry title="${%Stop on Terminate}" field="stopOnTerminate">
<f:checkbox />
</f:entry>
</f:advanced>

<f:entry title="">
@@ -24,13 +24,13 @@ protected void tearDown() throws Exception {

public void testConfigRoundtrip() throws Exception {
String ami = "ami1";
SlaveTemplate orig = new SlaveTemplate(ami, EC2Slave.TEST_ZONE, "foo", "22", InstanceType.M1Large, "ttt", "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g");
SlaveTemplate orig = new SlaveTemplate(ami, EC2Slave.TEST_ZONE, "foo", "22", InstanceType.M1Large, "ttt", "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", false);
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(ami);
assertEqualBeans(orig, received, "ami,zone,description,remoteFS,type,jvmopts");
assertEqualBeans(orig, received, "ami,zone,description,remoteFS,type,jvmopts,stopOnTerminate");
}
}
@@ -19,7 +19,7 @@ public class TemplateLabelsTest extends HudsonTestCase{
@Override
public void setUp() throws Exception{
super.setUp();
SlaveTemplate template = new SlaveTemplate("ami", "foo", "zone", "22", InstanceType.M1Large, LABEL1 + " " + LABEL2, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g");
SlaveTemplate template = new SlaveTemplate("ami", "foo", "zone", "22", InstanceType.M1Large, LABEL1 + " " + LABEL2, "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true);
List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(template);
ac = new AmazonEC2Cloud("us-east-1", "abc", "def", "ghi", "3", templates);
@@ -41,7 +41,7 @@ public void testLabelExpression() throws Exception{
}

public void testEmptyLabel() throws Exception{
SlaveTemplate temp = new SlaveTemplate("ami", "foo", "zone", "22", InstanceType.M1Large, "", "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g");
SlaveTemplate temp = new SlaveTemplate("ami", "foo", "zone", "22", InstanceType.M1Large, "", "foo ami", "bar", "aaa", "10", "rrr", "fff", "-Xmx1g", true);
List<SlaveTemplate> templates = new ArrayList<SlaveTemplate>();
templates.add(temp);
ac = new AmazonEC2Cloud("us-east-1", "abc", "def", "ghi", "3", templates);

0 comments on commit a2739cd

Please sign in to comment.