Skip to content

Commit

Permalink
Fix for JENKINS-15081. We store the EC2Cloud that a slave belongs to …
Browse files Browse the repository at this point in the history
…as an attribute in the EC2AbstractSlave class and have a function call to retrieve it in EC2Computer.

All references to EC2Cloud.get changed to EC2AbstractSlave.cloud or EC2Computer.getCloud().
This fix allows for us to always know the correct Cloud that an EC2AbstractSlave or EC2Computer belongs to so we can have multiple EC2Clouds configured on one Jenkins instance and have different templates for different clouds and have the instances for each spin up properly.
  • Loading branch information
rsennewald committed Apr 29, 2013
1 parent f4661e8 commit ec7e8e1
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 36 deletions.
27 changes: 14 additions & 13 deletions src/main/java/hudson/plugins/ec2/EC2AbstractSlave.java
Expand Up @@ -75,6 +75,7 @@ public abstract class EC2AbstractSlave extends Slave {
public final String idleTerminationMinutes;
public final boolean usePrivateDnsName;
public List<EC2Tag> tags;
public EC2Cloud cloud;

// Temporary stuff that is obtained live from EC2
public String publicDNS;
Expand All @@ -99,7 +100,7 @@ public abstract class EC2AbstractSlave extends Slave {


@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, boolean usePrivateDnsName) throws FormException, IOException {
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, EC2Cloud cloud, boolean usePrivateDnsName) throws FormException, IOException {

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

Expand All @@ -112,6 +113,7 @@ public EC2AbstractSlave(String name, String instanceId, String description, Stri
this.stopOnTerminate = stopOnTerminate;
this.idleTerminationMinutes = idleTerminationMinutes;
this.tags = tags;
this.cloud = cloud;
this.usePrivateDnsName = usePrivateDnsName;
}

Expand Down Expand Up @@ -164,13 +166,12 @@ public Computer createComputer() {
return new EC2Computer(this);
}

public static Instance getInstance(String instanceId) {
public static Instance getInstance(String instanceId, EC2Cloud cloud) {
DescribeInstancesRequest request = new DescribeInstancesRequest();
request.setInstanceIds(Collections.<String>singletonList(instanceId));
EC2Cloud cloudInstance = EC2Cloud.get();
if (cloudInstance == null)
if (cloud == null)
return null;
AmazonEC2 ec2 = cloudInstance.connect();
AmazonEC2 ec2 = cloud.connect();
List<Reservation> reservations = ec2.describeInstances(request).getReservations();
Instance i = null;
if (reservations.size() > 0) {
Expand All @@ -188,21 +189,21 @@ public static Instance getInstance(String instanceId) {

void stop() {
try {
AmazonEC2 ec2 = EC2Cloud.get().connect();
AmazonEC2 ec2 = cloud.connect();
StopInstancesRequest request = new StopInstancesRequest(
Collections.singletonList(getInstanceId()));
ec2.stopInstances(request);
LOGGER.info("EC2 instance stopped: " + getInstanceId());
toComputer().disconnect(null);
} catch (AmazonClientException e) {
Instance i = getInstance(getInstanceId());
Instance i = getInstance(getInstanceId(), cloud);
LOGGER.log(Level.WARNING, "Failed to terminate EC2 instance: "+getInstanceId() + " info: "+((i != null)?i:"") , e);
}
}

boolean terminateInstance() {
try {
AmazonEC2 ec2 = EC2Cloud.get().connect();
AmazonEC2 ec2 = cloud.connect();
TerminateInstancesRequest request = new TerminateInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.terminateInstances(request);
LOGGER.info("Terminated EC2 instance (terminated): "+getInstanceId());
Expand Down Expand Up @@ -280,7 +281,7 @@ protected void fetchLiveInstanceData( boolean force ) throws AmazonClientExcepti
return;
}

Instance i = getInstance(getInstanceId());
Instance i = getInstance(getInstanceId(), cloud);

lastFetchTime = now;
lastFetchInstance = i;
Expand All @@ -298,7 +299,7 @@ protected void fetchLiveInstanceData( boolean force ) throws AmazonClientExcepti

/* Clears all existing tag data so that we can force the instance into a known state */
protected void clearLiveInstancedata() throws AmazonClientException {
Instance inst = getInstance(getInstanceId());
Instance inst = getInstance(getInstanceId(), cloud);

/* Now that we have our instance, we can clear the tags on it */
if (!tags.isEmpty()) {
Expand All @@ -310,14 +311,14 @@ protected void clearLiveInstancedata() throws AmazonClientException {

DeleteTagsRequest tag_request = new DeleteTagsRequest();
tag_request.withResources(inst.getInstanceId()).setTags(inst_tags);
EC2Cloud.get().connect().deleteTags(tag_request);
cloud.connect().deleteTags(tag_request);
}
}


/* Sets tags on an instance. This will not clear existing tag data, so call clearLiveInstancedata if needed */
protected void pushLiveInstancedata() throws AmazonClientException {
Instance inst = getInstance(getInstanceId());
Instance inst = getInstance(getInstanceId(), cloud);

/* Now that we have our instance, we can set tags on it */
if (tags != null && !tags.isEmpty()) {
Expand All @@ -329,7 +330,7 @@ protected void pushLiveInstancedata() throws AmazonClientException {

CreateTagsRequest tag_request = new CreateTagsRequest();
tag_request.withResources(inst.getInstanceId()).setTags(inst_tags);
EC2Cloud.get().connect().createTags(tag_request);
cloud.connect().createTags(tag_request);
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/java/hudson/plugins/ec2/EC2Computer.java
Expand Up @@ -70,12 +70,17 @@ public String getSpotInstanceRequestId(){
}
return "";
}

public EC2Cloud getCloud() {
EC2Slave node = (EC2Slave) super.getNode();
return node.cloud;
}

/**
* Gets the EC2 console output.
*/
public String getConsoleOutput() throws AmazonClientException {
AmazonEC2 ec2 = EC2Cloud.get().connect();
AmazonEC2 ec2 = getCloud().connect();
GetConsoleOutputRequest request = new GetConsoleOutputRequest(getInstanceId());
return ec2.getConsoleOutput(request).getOutput();
}
Expand Down Expand Up @@ -150,7 +155,7 @@ private Instance _describeInstance() throws AmazonClientException, InterruptedEx
private Instance _describeInstanceOnce() throws AmazonClientException {
DescribeInstancesRequest request = new DescribeInstancesRequest();
request.setInstanceIds(Collections.<String>singletonList(getNode().getInstanceId()));
return EC2Cloud.get().connect().describeInstances(request).getReservations().get(0).getInstances().get(0);
return getCloud().connect().describeInstances(request).getReservations().get(0).getInstances().get(0);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/hudson/plugins/ec2/EC2ComputerLauncher.java
Expand Up @@ -61,7 +61,7 @@ public void launch(SlaveComputer _computer, TaskListener listener) {
case RUNNING:
break OUTER;
case STOPPED:
AmazonEC2 ec2 = EC2Cloud.get().connect();
AmazonEC2 ec2 = computer.getCloud().connect();
List<String> instances = new ArrayList<String>();
instances.add(computer.getInstanceId());

Expand Down
16 changes: 8 additions & 8 deletions src/main/java/hudson/plugins/ec2/EC2OndemandSlave.java
Expand Up @@ -33,18 +33,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) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, labelString, Mode.NORMAL, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, false);
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, EC2Cloud cloud) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, labelString, Mode.NORMAL, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloud, false);
}

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, boolean usePrivateDnsName) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, labelString, Mode.NORMAL, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, usePrivateDnsName);
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, EC2Cloud cloud, boolean usePrivateDnsName) throws FormException, IOException {
this(instanceId, description, remoteFS, sshPort, numExecutors, labelString, Mode.NORMAL, initScript, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, publicDNS, privateDNS, tags, cloud, usePrivateDnsName);
}

@DataBoundConstructor
public EC2OndemandSlave(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, boolean usePrivateDnsName) throws FormException, IOException {
public EC2OndemandSlave(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, EC2Cloud cloud, boolean usePrivateDnsName) throws FormException, IOException {

super(description + " (" + instanceId + ")", instanceId, description, remoteFS, sshPort, numExecutors, mode, labelString, new EC2UnixLauncher(), new EC2RetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, false, idleTerminationMinutes, tags, usePrivateDnsName);
super(description + " (" + instanceId + ")", instanceId, description, remoteFS, sshPort, numExecutors, mode, labelString, new EC2UnixLauncher(), new EC2RetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, false, idleTerminationMinutes, tags, cloud, usePrivateDnsName);

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


Expand All @@ -67,7 +67,7 @@ public void terminate() {
/* The node has been killed externally, so we've nothing to do here */
LOGGER.info("EC2 instance already terminated: "+getInstanceId());
} else {
AmazonEC2 ec2 = EC2Cloud.get().connect();
AmazonEC2 ec2 = cloud.connect();
TerminateInstancesRequest request = new TerminateInstancesRequest(Collections.singletonList(getInstanceId()));
ec2.terminateInstances(request);
LOGGER.info("Terminated EC2 instance (terminated): "+getInstanceId());
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/hudson/plugins/ec2/EC2SpotSlave.java
Expand Up @@ -30,14 +30,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, boolean usePrivateDnsName) throws FormException, IOException {
this(name, spotInstanceRequestId, description, remoteFS, sshPort, numExecutors, mode, initScript, labelString, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, idleTerminationMinutes, tags, usePrivateDnsName);
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, EC2Cloud cloud, boolean usePrivateDnsName) throws FormException, IOException {
this(name, spotInstanceRequestId, description, remoteFS, sshPort, numExecutors, mode, initScript, labelString, Collections.<NodeProperty<?>>emptyList(), remoteAdmin, rootCommandPrefix, jvmopts, idleTerminationMinutes, tags, cloud, usePrivateDnsName);
}

@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, boolean usePrivateDnsName) throws FormException, IOException {
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, EC2Cloud cloud, boolean usePrivateDnsName) throws FormException, IOException {

super(name, "", description, remoteFS, sshPort, numExecutors, mode, labelString, new EC2SpotComputerLauncher(), new EC2SpotRetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, false, idleTerminationMinutes, tags, usePrivateDnsName);
super(name, "", description, remoteFS, sshPort, numExecutors, mode, labelString, new EC2SpotComputerLauncher(), new EC2SpotRetentionStrategy(idleTerminationMinutes), initScript, nodeProperties, remoteAdmin, rootCommandPrefix, jvmopts, false, idleTerminationMinutes, tags, cloud, usePrivateDnsName);

this.name = name;
this.spotInstanceRequestId = spotInstanceRequestId;
Expand Down Expand Up @@ -89,9 +89,8 @@ public void terminate() {
}

private AmazonEC2 getEc2Cloud(){
EC2Cloud cloudInstance = EC2Cloud.get();
if (cloudInstance == null) return null;
return cloudInstance.connect();
if (cloud == null) return null;
return cloud.connect();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/hudson/plugins/ec2/SlaveTemplate.java
Expand Up @@ -455,11 +455,11 @@ private EC2AbstractSlave provisionSpot(TaskListener listener) throws AmazonClien
}

private EC2OndemandSlave newOndemandSlave(Instance inst) throws FormException, IOException {
return new EC2OndemandSlave(inst.getInstanceId(), description, remoteFS, getSshPort(), getNumExecutors(), labels, mode, initScript, remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, inst.getPublicDnsName(), inst.getPrivateDnsName(), EC2Tag.fromAmazonTags(inst.getTags()), usePrivateDnsName);
return new EC2OndemandSlave(inst.getInstanceId(), description, remoteFS, getSshPort(), getNumExecutors(), labels, mode, initScript, remoteAdmin, rootCommandPrefix, jvmopts, stopOnTerminate, idleTerminationMinutes, inst.getPublicDnsName(), inst.getPrivateDnsName(), EC2Tag.fromAmazonTags(inst.getTags()), parent, usePrivateDnsName);
}

private EC2SpotSlave newSpotSlave(SpotInstanceRequest sir, String name) throws FormException, IOException {
return new EC2SpotSlave(name, sir.getSpotInstanceRequestId(), description, remoteFS, getSshPort(), getNumExecutors(), mode, initScript, labels, remoteAdmin, rootCommandPrefix, jvmopts, idleTerminationMinutes, EC2Tag.fromAmazonTags(sir.getTags()), usePrivateDnsName);
return new EC2SpotSlave(name, sir.getSpotInstanceRequestId(), description, remoteFS, getSshPort(), getNumExecutors(), mode, initScript, labels, remoteAdmin, rootCommandPrefix, jvmopts, idleTerminationMinutes, EC2Tag.fromAmazonTags(sir.getTags()), parent, usePrivateDnsName);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java
Expand Up @@ -83,7 +83,7 @@ else if (bootstrapResult == SAMEUSER)
else {
// connect fresh as ROOT
cleanupConn = connectToSsh(computer, logger);
KeyPair key = EC2Cloud.get().getKeyPair();
KeyPair key = computer.getCloud().getKeyPair();
if (!cleanupConn.authenticateWithPublicKey(computer.getRemoteAdmin(), key.getKeyMaterial().toCharArray(), "")) {
logger.println("Authentication failed");
return; // failed to connect as root.
Expand Down Expand Up @@ -125,7 +125,7 @@ else if (bootstrapResult == SAMEUSER)
String jdk = "java1.6.0_12";
String path = "/hudson-ci/jdk/linux-i586/" + jdk + ".tgz";

URL url = EC2Cloud.get().buildPresignedURL(path);
URL url = computer.getCloud().buildPresignedURL(path);
if(conn.exec("wget -nv -O /tmp/" + jdk + ".tgz '" + url + "'", logger) !=0) {
logger.println("Failed to download Java");
return;
Expand Down Expand Up @@ -173,7 +173,7 @@ private int bootstrap(Connection bootstrapConn, EC2Computer computer, PrintStrea
try {
int tries = 20;
boolean isAuthenticated = false;
KeyPair key = EC2Cloud.get().getKeyPair();
KeyPair key = computer.getCloud().getKeyPair();
while (tries-- > 0) {
logger.println("Authenticating as " + computer.getRemoteAdmin());
isAuthenticated = bootstrapConn.authenticateWithPublicKey(computer.getRemoteAdmin(), key.getKeyMaterial().toCharArray(), "");
Expand Down

0 comments on commit ec7e8e1

Please sign in to comment.