1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.tools.ant.util;
20
21 import java.io.IOException;
22 import java.util.concurrent.TimeoutException;
23
24 import org.apache.tools.ant.BuildException;
25 import org.apache.tools.ant.Project;
26 import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
27 import org.apache.tools.ant.taskdefs.PumpStreamHandler;
28 import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo;
29 import org.apache.tools.ant.util.FileUtils;
30
31 import com.jcraft.jsch.ChannelExec;
32 import com.jcraft.jsch.JSch;
33 import com.jcraft.jsch.JSchException;
34 import com.jcraft.jsch.Session;
35
36
37
38
39
40
41
42
43
44
45 public class SSHExecute {
46
47 private static final int RETRY_INTERVAL = 500;
48
49
50 private long maxwait = 0;
51
52 private ExecuteStreamHandler streamHandler;
53 private String host;
54 private SSHUserInfo userInfo;
55 private int port = 22;
56 private Project project;
57 private String knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
58
59
60
61
62 public SSHExecute() {
63 this(new PumpStreamHandler());
64 }
65
66
67
68
69
70
71
72 public SSHExecute(ExecuteStreamHandler streamHandler) {
73 setStreamHandler(streamHandler);
74 userInfo = new SSHUserInfo();
75 }
76
77
78
79
80
81
82
83 public void setStreamHandler(ExecuteStreamHandler streamHandler) {
84 this.streamHandler = streamHandler;
85 }
86
87
88
89
90
91
92
93 public void setTrust(boolean yesOrNo) {
94 userInfo.setTrust(yesOrNo);
95 }
96
97
98
99
100 public void setProject(Project project) {
101 this.project = project;
102 }
103
104
105
106
107
108
109
110 public void setUsername(String username) {
111 userInfo.setName(username);
112 }
113
114
115
116
117
118
119
120 public void setPassword(String password) {
121 userInfo.setPassword(password);
122 }
123
124
125
126
127
128
129
130 public void setKeyfile(String keyfile) {
131 userInfo.setKeyfile(keyfile);
132 }
133
134
135
136
137
138
139
140 public void setPassphrase(String passphrase) {
141 userInfo.setPassphrase(passphrase);
142 }
143
144
145
146
147
148
149
150 public void setHost(String host) {
151 this.host = host;
152 }
153
154
155
156
157
158
159
160 public void setPort(int port) {
161 this.port = port;
162 }
163
164
165
166
167
168
169
170
171 public void setTimeout(long timeout) {
172 maxwait = timeout;
173 }
174
175
176
177
178
179
180
181
182
183 public void setKnownhosts(String knownHosts) {
184 this.knownHosts = knownHosts;
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 public int execute(String command) throws BuildException, JSchException, IOException,
204 TimeoutException {
205 if (command == null) {
206 throw new BuildException("Command is required.");
207 }
208 if (host == null) {
209 throw new BuildException("Host is required.");
210 }
211 if (userInfo.getName() == null) {
212 throw new BuildException("Username is required.");
213 }
214 if (userInfo.getKeyfile() == null && userInfo.getPassword() == null) {
215 throw new BuildException("Password or Keyfile is required.");
216 }
217
218 Session session = null;
219 try {
220 session = openSession();
221 return executeCommand(session, command);
222 } finally {
223 if (session != null && session.isConnected()) {
224 session.disconnect();
225 }
226 }
227 }
228
229
230
231
232
233
234
235
236 protected Session openSession() throws JSchException {
237 JSch jsch = new JSch();
238 if (null != userInfo.getKeyfile()) {
239 jsch.addIdentity(userInfo.getKeyfile());
240 }
241
242 if (!userInfo.getTrust() && knownHosts != null) {
243 project.log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
244 jsch.setKnownHosts(knownHosts);
245 }
246
247 Session session = jsch.getSession(userInfo.getName(), host, port);
248 session.setUserInfo(userInfo);
249 project.log("Connecting to " + host + ":" + port, Project.MSG_VERBOSE);
250 session.connect();
251 return session;
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 private int executeCommand(Session session, String cmd) throws JSchException, IOException,
269 TimeoutException {
270 final ChannelExec channel;
271 session.setTimeout((int) maxwait);
272
273 channel = (ChannelExec) session.openChannel("exec");
274 channel.setCommand(cmd);
275 attachStreams(channel);
276 project.log("executing command: " + cmd, Project.MSG_VERBOSE);
277 channel.connect();
278 try {
279 waitFor(channel);
280 } finally {
281 streamHandler.stop();
282 closeStreams(channel);
283 }
284 return channel.getExitStatus();
285 }
286
287 private void attachStreams(final ChannelExec channel) throws IOException {
288 streamHandler.setProcessInputStream(channel.getOutputStream());
289 streamHandler.setProcessOutputStream(channel.getInputStream());
290 streamHandler.setProcessErrorStream(channel.getErrStream());
291 streamHandler.start();
292 }
293
294
295
296
297
298
299
300
301 public static void closeStreams(ChannelExec process) throws IOException {
302 FileUtils.close(process.getInputStream());
303 FileUtils.close(process.getOutputStream());
304 FileUtils.close(process.getErrStream());
305 }
306
307
308
309
310 @SuppressWarnings("deprecation")
311 private void waitFor(final ChannelExec channel) throws TimeoutException {
312
313 Thread thread = new Thread() {
314 public void run() {
315 while (!channel.isClosed()) {
316 try {
317 sleep(RETRY_INTERVAL);
318 } catch (InterruptedException e) {
319
320 }
321 }
322 }
323 };
324
325 thread.start();
326 try {
327 thread.join(maxwait);
328 } catch (InterruptedException e) {
329
330 }
331
332 if (thread.isAlive()) {
333 thread.destroy();
334 throw new TimeoutException("command still running");
335 }
336 }
337
338 }