package hudson.plugins.ec2;
import hudson.Extension;
import hudson.model.Descriptor.FormException;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.plugins.ec2.ssh.EC2UnixLauncher;
import hudson.plugins.ec2.win.EC2WindowsLauncher;
import hudson.slaves.NodeProperty;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import com.amazonaws.AmazonClientException;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.model.*;
/**
* Slave running on EC2.
*
* @author Kohsuke Kawaguchi
*/
public final class EC2OndemandSlave extends EC2AbstractSlave {
private static final Logger LOGGER = Logger.getLogger(EC2OndemandSlave.class.getName());
public EC2OndemandSlave(String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, String tmpDir, String remoteAdmin, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName, int launchTimeout, AMITypeData amiType)
throws FormException, IOException {
this(description + " (" + instanceId + ")", instanceId, description, remoteFS, numExecutors, labelString, mode, initScript, tmpDir, Collections.<NodeProperty<?>> emptyList(), remoteAdmin, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloudName, false, false, launchTimeout, amiType);
}
public EC2OndemandSlave(String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, String tmpDir, String remoteAdmin, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout, AMITypeData amiType)
throws FormException, IOException {
this(description + " (" + instanceId + ")", instanceId, description, remoteFS, numExecutors, labelString, mode, initScript, tmpDir, Collections.<NodeProperty<?>> emptyList(), remoteAdmin, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloudName, usePrivateDnsName, useDedicatedTenancy, launchTimeout, amiType);
}
@DataBoundConstructor
public EC2OndemandSlave(String name, String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, String tmpDir, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout, AMITypeData amiType)
throws FormException, IOException {
super(name, instanceId, description, remoteFS, numExecutors, mode, labelString, amiType.isWindows() ? new EC2WindowsLauncher()
: new EC2UnixLauncher(), new EC2RetentionStrategy(idleTerminationMinutes), initScript, tmpDir, nodeProperties, remoteAdmin, jvmopts, stopOnTerminate, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, useDedicatedTenancy, launchTimeout, amiType);
this.publicDNS = publicDNS;
this.privateDNS = privateDNS;
}
/**
* Constructor for debugging.
*/
public EC2OndemandSlave(String instanceId) throws FormException, IOException {
this(instanceId, instanceId, "debug", "/tmp/hudson", 1, "debug", Mode.NORMAL, "", "/tmp", Collections.<NodeProperty<?>> emptyList(), null, null, false, null, "Fake public", "Fake private", null, null, false, false, 0, new UnixData(null, null));
}
/**
* Terminates the instance in EC2.
*/
public void terminate() {
try {
if (!isAlive(true)) {
/*
* The node has been killed externally, so we've nothing to do here
*/
LOGGER.info("EC2 instance already terminated: " + getInstanceId());
} else {
AmazonEC2 ec2 = getCloud().connect();
TerminateInstancesRequest request = new TerminateInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.terminateInstances(request);
LOGGER.info("Terminated EC2 instance (terminated): " + getInstanceId());
}
Jenkins.getInstance().removeNode(this);
LOGGER.info("Removed EC2 instance from jenkins master: " + getInstanceId());
} catch (AmazonClientException e) {
LOGGER.log(Level.WARNING, "Failed to terminate EC2 instance: " + getInstanceId(), e);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to terminate EC2 instance: " + getInstanceId(), e);
}
}
@Override
public Node reconfigure(final StaplerRequest req, JSONObject form) throws FormException {
if (form == null) {
return null;
}
if (!isAlive(true)) {
LOGGER.info("EC2 instance terminated externally: " + getInstanceId());
try {
Jenkins.getInstance().removeNode(this);
} catch (IOException ioe) {
LOGGER.log(Level.WARNING, "Attempt to reconfigure EC2 instance which has been externally terminated: "
+ getInstanceId(), ioe);
}
return null;
}
return super.reconfigure(req, form);
}
@Extension
public static final class DescriptorImpl extends EC2AbstractSlave.DescriptorImpl {
@Override
public String getDisplayName() {
return Messages.EC2OndemandSlave_AmazonEC2();
}
}
@Override
public String getEc2Type() {
return Messages.EC2OndemandSlave_OnDemand();
}
}