-
Notifications
You must be signed in to change notification settings - Fork 690
/
EC2WindowsLauncher.java
153 lines (127 loc) · 6.89 KB
/
EC2WindowsLauncher.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package hudson.plugins.ec2.win;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.plugins.ec2.EC2Computer;
import hudson.plugins.ec2.EC2ComputerLauncher;
import hudson.plugins.ec2.win.winrm.WindowsProcess;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Listener;
import hudson.slaves.ComputerLauncher;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import com.amazonaws.AmazonClientException;
import com.amazonaws.services.ec2.model.Instance;
public class EC2WindowsLauncher extends EC2ComputerLauncher {
final long sleepBetweenAttemps = TimeUnit.SECONDS.toMillis(10);
@Override
protected void launch(EC2Computer computer, PrintStream logger, Instance inst) throws IOException, AmazonClientException,
InterruptedException {
final WinConnection connection = connectToWinRM(computer, logger);
try {
String initScript = computer.getNode().initScript;
String tmpDir = (computer.getNode().tmpDir != null && !computer.getNode().tmpDir.equals("") ? computer.getNode().tmpDir : "C:\\Windows\\Temp\\");
logger.println("Creating tmp directory if it does not exist");
connection.execute("if not exist " + tmpDir + " mkdir " + tmpDir);
if(initScript!=null && initScript.trim().length()>0 && !connection.exists(tmpDir + ".jenkins-init")) {
logger.println("Executing init script");
OutputStream init = connection.putFile(tmpDir + "init.bat");
init.write(initScript.getBytes("utf-8"));
WindowsProcess initProcess = connection.execute("cmd /c " + tmpDir + "init.bat");
IOUtils.copy(initProcess.getStdout(),logger);
int exitStatus = initProcess.waitFor();
if (exitStatus!=0) {
logger.println("init script failed: exit code="+exitStatus);
return;
}
OutputStream initGuard = connection.putFile(tmpDir + ".jenkins-init");
initGuard.write("init ran".getBytes());
logger.println("init script failed ran successfully");
}
OutputStream slaveJar = connection.putFile(tmpDir + "slave.jar");
slaveJar.write(Hudson.getInstance().getJnlpJars("slave.jar").readFully());
logger.println("slave.jar sent remotely. Bootstrapping it");
final String jvmopts = computer.getNode().jvmopts;
final WindowsProcess process = connection.execute("java " + (jvmopts != null ? jvmopts : "") + " -jar " + tmpDir + "slave.jar", 86400);
computer.setChannel(process.getStdout(), process.getStdin(), logger, new Listener() {
@Override
public void onClosed(Channel channel, IOException cause) {
process.destroy();
connection.close();
}
});
} catch (Throwable ioe) {
logger.println("Ouch:");
ioe.printStackTrace(logger);
} finally {
connection.close();
}
}
private WinConnection connectToWinRM(EC2Computer computer, PrintStream logger) throws AmazonClientException,
InterruptedException {
final long timeout = computer.getNode().getLaunchTimeoutInMillis();
final long startTime = System.currentTimeMillis();
logger.println(computer.getNode().getDisplayName() + " booted at " + computer.getNode().getCreatedTime());
boolean alreadyBooted = (startTime - computer.getNode().getCreatedTime()) > TimeUnit.MINUTES.toMillis(3);
while (true) {
try {
long waitTime = System.currentTimeMillis() - startTime;
if (waitTime > timeout) {
throw new AmazonClientException("Timed out after " + (waitTime / 1000)
+ " seconds of waiting for winrm to be connected");
}
Instance instance = computer.updateInstanceDescription();
String vpc_id = instance.getVpcId();
String ip, host;
if (computer.getNode().usePrivateDnsName) {
host = instance.getPrivateDnsName();
ip = instance.getPrivateIpAddress(); // SmbFile doesn't quite work with hostnames
} else {
host = instance.getPublicDnsName();
if (host == null || host.equals("")) {
host = instance.getPrivateDnsName();
ip = instance.getPrivateIpAddress(); // SmbFile doesn't quite work with hostnames
}
else {
host = instance.getPublicDnsName();
ip = instance.getPublicIpAddress(); // SmbFile doesn't quite work with hostnames
}
}
if ("0.0.0.0".equals(host)) {
logger.println("Invalid host 0.0.0.0, your host is most likely waiting for an ip address.");
throw new IOException("goto sleep");
}
logger.println("Connecting to " + host + "(" + ip + ") with WinRM as " + computer.getNode().remoteAdmin);
WinConnection connection = new WinConnection(ip, computer.getNode().remoteAdmin, computer.getNode().getAdminPassword());
connection.setUseHTTPS(computer.getNode().isUseHTTPS());
if (!connection.ping()) {
logger.println("Waiting for WinRM to come up. Sleeping 10s.");
Thread.sleep(sleepBetweenAttemps);
continue;
}
if (!alreadyBooted || computer.getNode().stopOnTerminate) {
logger.println("WinRM service responded. Waiting for WinRM service to stabilize on " + computer.getNode().getDisplayName());
Thread.sleep(computer.getNode().getBootDelay());
alreadyBooted = true;
logger.println("WinRM should now be ok on " + computer.getNode().getDisplayName());
if (!connection.ping()) {
logger.println("WinRM not yet up. Sleeping 10s.");
Thread.sleep(sleepBetweenAttemps);
continue;
}
}
logger.println("Connected with WinRM.");
return connection; // successfully connected
} catch (IOException e) {
logger.println("Waiting for WinRM to come up. Sleeping 10s.");
Thread.sleep(sleepBetweenAttemps);
}
}
}
@Override
public Descriptor<ComputerLauncher> getDescriptor() {
throw new UnsupportedOperationException();
}
}