Skip to content

Commit

Permalink
JENKINS-4995 Support Windows AMIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Francis Upton IV committed Jul 29, 2014
1 parent 04cd780 commit 859dd4e
Show file tree
Hide file tree
Showing 41 changed files with 2,176 additions and 72 deletions.
20 changes: 20 additions & 0 deletions pom.xml
Expand Up @@ -71,6 +71,25 @@ THE SOFTWARE.
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>node-iterator-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
<!-- force version 4.1.1 because of 4.1 bug:
https://issues.apache.org/jira/browse/HTTPCLIENT-1056
that prevents authentication caching, resulting in very
poor performances for WinRM -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.3</version>
</dependency>
</dependencies>

Expand Down Expand Up @@ -102,6 +121,7 @@ THE SOFTWARE.
<url>http://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>

<build>
<pluginManagement>
<plugins>
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/hudson/plugins/ec2/AMITypeData.java
@@ -0,0 +1,9 @@
package hudson.plugins.ec2;

import hudson.model.AbstractDescribableImpl;

public abstract class AMITypeData extends AbstractDescribableImpl<AMITypeData>
{
public abstract boolean isWindows();
public abstract boolean isUnix();
}
72 changes: 59 additions & 13 deletions src/main/java/hudson/plugins/ec2/EC2AbstractSlave.java
Expand Up @@ -25,6 +25,7 @@

import hudson.Util;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.model.Descriptor.FormException;
Expand Down Expand Up @@ -67,14 +68,16 @@ public abstract class EC2AbstractSlave extends Slave {
*/
public final String initScript;
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;
public final String idleTerminationMinutes;
public final boolean usePrivateDnsName;
public final boolean useDedicatedTenancy;
public List<EC2Tag> tags;
public final String cloudName;
public AMITypeData amiType;

// Temporary stuff that is obtained live from EC2
public String publicDNS;
Expand All @@ -90,33 +93,37 @@ public abstract class EC2AbstractSlave extends Slave {
protected static final long MIN_FETCH_TIME = 20 * 1000;


/**
* For data read from old Hudson, this is 0, so we use that to indicate 22.
*/
protected final int sshPort;
protected final int launchTimeout;

// Deprecated by the AMITypeData data structure
@Deprecated
protected transient int sshPort;
@Deprecated
public transient String rootCommandPrefix; // e.g. 'sudo'

private transient long createdTime;

public static final String TEST_ZONE = "testZone";


@DataBoundConstructor
public EC2AbstractSlave(String name, String instanceId, String description, String remoteFS, int sshPort, int numExecutors, Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy<EC2Computer> retentionStrategy, String initScript, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout) throws FormException, IOException {
public EC2AbstractSlave(String name, String instanceId, String description, String remoteFS, int numExecutors, Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy<EC2Computer> retentionStrategy, String initScript, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout, AMITypeData amiType) throws FormException, IOException {

super(name, "", remoteFS, numExecutors, mode, labelString, launcher, retentionStrategy, nodeProperties);

this.instanceId = instanceId;
this.initScript = initScript;
this.remoteAdmin = remoteAdmin;
this.rootCommandPrefix = rootCommandPrefix;
this.jvmopts = jvmopts;
this.sshPort = sshPort;
this.stopOnTerminate = stopOnTerminate;
this.idleTerminationMinutes = idleTerminationMinutes;
this.tags = tags;
this.usePrivateDnsName = usePrivateDnsName;
this.useDedicatedTenancy = useDedicatedTenancy;
this.cloudName = cloudName;
this.launchTimeout = launchTimeout;
this.amiType = amiType;
readResolve();
}

protected Object readResolve() {
Expand All @@ -129,6 +136,11 @@ protected Object readResolve() {
if (instanceId == null) {
instanceId = getNodeName();
}

if (amiType == null) {
amiType = new UnixData(rootCommandPrefix, Integer.toString(sshPort));
}

return this;
}

Expand Down Expand Up @@ -264,22 +276,32 @@ public long getLaunchTimeoutInMillis() {

String getRemoteAdmin() {
if (remoteAdmin == null || remoteAdmin.length() == 0)
return "root";
return amiType.isWindows() ? "Administrator" : "root";
return remoteAdmin;
}

String getRootCommandPrefix() {
if (rootCommandPrefix == null || rootCommandPrefix.length() == 0)
String commandPrefix = amiType.isUnix() ? ((UnixData)amiType).getRootCommandPrefix() : "";
if (commandPrefix == null || commandPrefix.length() == 0)
return "";
return rootCommandPrefix + " ";
return commandPrefix + " ";
}

String getJvmopts() {
return Util.fixNull(jvmopts);
}

public int getSshPort() {
return sshPort!=0 ? sshPort : 22;
String sshPort = amiType.isUnix() ? ((UnixData)amiType).getSshPort() : "22";
if (sshPort == null || sshPort.length() == 0)
return 22;

int port = 0;
try {
port = Integer.parseInt(sshPort);
} catch (Exception e) {
}
return port!=0 ? port : 22;
}

public boolean getStopOnTerminate() {
Expand Down Expand Up @@ -320,6 +342,7 @@ protected void fetchLiveInstanceData( boolean force ) throws AmazonClientExcepti

publicDNS = i.getPublicDnsName();
privateDNS = i.getPrivateIpAddress();
createdTime = i.getLaunchTime().getTime();
tags = new LinkedList<EC2Tag>();

for (Tag t : i.getTags()) {
Expand Down Expand Up @@ -380,9 +403,26 @@ public List<EC2Tag> getTags() {
return Collections.unmodifiableList(tags);
}

public long getCreatedTime() {
fetchLiveInstanceData(false);
return createdTime;
}

public boolean getUsePrivateDnsName() {
return usePrivateDnsName;
}

public String getAdminPassword() {
return amiType.isWindows() ? ((WindowsData)amiType).getPassword() : "";
}

public boolean isUseHTTPS() {
return amiType.isWindows() ? ((WindowsData)amiType).isUseHTTPS() : false;
}

public int getBootDelay() {
return amiType.isWindows() ? ((WindowsData)amiType).getBootDelayInMillis() : 0;
}

public static ListBoxModel fillZoneItems(String accessId, String secretKey, String region) throws IOException, ServletException {
ListBoxModel model = new ListBoxModel();
Expand All @@ -408,7 +448,7 @@ public static ListBoxModel fillZoneItems(String accessId, String secretKey, Stri
*/
abstract public String getEc2Type();

public static abstract class DescriptorImpl extends SlaveDescriptor {
public static abstract class DescriptorImpl extends SlaveDescriptor {

@Override
public abstract String getDisplayName();
Expand All @@ -423,7 +463,13 @@ public ListBoxModel doFillZoneItems(@QueryParameter String accessId,
ServletException {
return fillZoneItems(accessId, secretKey, region);
}

public List<Descriptor<AMITypeData>> getAMITypeDescriptors()
{
return Hudson.getInstance().<AMITypeData,Descriptor<AMITypeData>>getDescriptorList(AMITypeData.class);
}
}

private static final Logger LOGGER = Logger.getLogger(EC2AbstractSlave.class.getName());

}
15 changes: 8 additions & 7 deletions src/main/java/hudson/plugins/ec2/EC2OndemandSlave.java
Expand Up @@ -5,6 +5,7 @@
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;
Expand All @@ -29,18 +30,18 @@
*/
public final class EC2OndemandSlave extends EC2AbstractSlave {

public EC2OndemandSlave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, String labelString, Mode mode, String initScript, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName,int launchTimeout) throws FormException, IOException {
this(description + " (" + instanceId + ")", instanceId, description, remoteFS, sshPort, numExecutors, labelString, mode, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloudName, false, false, launchTimeout);
public EC2OndemandSlave(String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, 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, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloudName, false, false, launchTimeout, amiType);
}

public EC2OndemandSlave(String instanceId, String description, String remoteFS, int sshPort, int numExecutors, String labelString, Mode mode, String initScript, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout) throws FormException, IOException {
this(description + " (" + instanceId + ")", instanceId, description, remoteFS, sshPort, numExecutors, labelString, mode, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloudName, usePrivateDnsName, useDedicatedTenancy, launchTimeout);
public EC2OndemandSlave(String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, 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, 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 sshPort, int numExecutors, String labelString, Mode mode, String initScript, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String rootCommandPrefix, String jvmopts, boolean stopOnTerminate, String idleTerminationMinutes, String publicDNS, String privateDNS, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, boolean useDedicatedTenancy, int launchTimeout) throws FormException, IOException {
public EC2OndemandSlave(String name, String instanceId, String description, String remoteFS, int numExecutors, String labelString, Mode mode, String initScript, 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, sshPort, numExecutors, mode, labelString, new EC2UnixLauncher(), new EC2RetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, useDedicatedTenancy, launchTimeout);
super(name, instanceId, description, remoteFS, numExecutors, mode, labelString, amiType.isWindows() ? new EC2WindowsLauncher() : new EC2UnixLauncher(), new EC2RetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, jvmopts, stopOnTerminate, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, useDedicatedTenancy, launchTimeout, amiType);

this.publicDNS = publicDNS;
this.privateDNS = privateDNS;
Expand All @@ -50,7 +51,7 @@ public EC2OndemandSlave(String name, String instanceId, String description, Stri
* Constructor for debugging.
*/
public EC2OndemandSlave(String instanceId) throws FormException, IOException {
this(instanceId, instanceId, "debug", "/tmp/hudson", 22, 1, "debug", Mode.NORMAL, "", Collections.<NodeProperty<?>>emptyList(), null, null, null, false, null, "Fake public", "Fake private", null, null, false, false, 0);
this(instanceId, instanceId, "debug", "/tmp/hudson", 1, "debug", Mode.NORMAL, "", Collections.<NodeProperty<?>>emptyList(), null, null, false, null, "Fake public", "Fake private", null, null, false, false, 0, new UnixData(null, null));
}


Expand Down
9 changes: 4 additions & 5 deletions src/main/java/hudson/plugins/ec2/EC2SpotSlave.java
Expand Up @@ -26,15 +26,14 @@ public final class EC2SpotSlave extends EC2AbstractSlave {

private final String spotInstanceRequestId;

public EC2SpotSlave(String name, String spotInstanceRequestId, String description, String remoteFS, int sshPort, int numExecutors, Mode mode, String initScript, String labelString, String remoteAdmin, String rootCommandPrefix, String jvmopts, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, int launchTimeout) throws FormException, IOException {
this(name, spotInstanceRequestId, description, remoteFS, sshPort, numExecutors, mode, initScript, labelString, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, launchTimeout);
public EC2SpotSlave(String name, String spotInstanceRequestId, String description, String remoteFS, int numExecutors, Mode mode, String initScript, String labelString, String remoteAdmin, String jvmopts, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, int launchTimeout, AMITypeData amiType) throws FormException, IOException {
this(name, spotInstanceRequestId, description, remoteFS, numExecutors, mode, initScript, labelString, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, jvmopts, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, launchTimeout, amiType);
}

@DataBoundConstructor
public EC2SpotSlave(String name, String spotInstanceRequestId, String description, String remoteFS, int sshPort, int numExecutors, Mode mode, String initScript, String labelString, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String rootCommandPrefix, String jvmopts, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, int launchTimeout) throws FormException, IOException {

super(name, "", description, remoteFS, sshPort, numExecutors, mode, labelString, new EC2SpotComputerLauncher(), new EC2SpotRetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, false, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, false, launchTimeout);
public EC2SpotSlave(String name, String spotInstanceRequestId, String description, String remoteFS, int numExecutors, Mode mode, String initScript, String labelString, List<? extends NodeProperty<?>> nodeProperties, String remoteAdmin, String jvmopts, String idleTerminationMinutes, List<EC2Tag> tags, String cloudName, boolean usePrivateDnsName, int launchTimeout, AMITypeData amiType) throws FormException, IOException {

super(name, "", description, remoteFS, numExecutors, mode, labelString, new EC2SpotComputerLauncher(), new EC2SpotRetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, jvmopts, false, idleTerminationMinutes, tags, cloudName, usePrivateDnsName, false, launchTimeout, amiType);
this.name = name;
this.spotInstanceRequestId = spotInstanceRequestId;
}
Expand Down

0 comments on commit 859dd4e

Please sign in to comment.