mirror of https://github.com/apache/jclouds.git
revamped task so that it has no external deps. Added patched SSHExec task
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2581 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
7d70031a29
commit
53c6a2376a
|
@ -33,11 +33,6 @@
|
||||||
<jclouds.test.listener></jclouds.test.listener>
|
<jclouds.test.listener></jclouds.test.listener>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.shrinkwrap</groupId>
|
|
||||||
<artifactId>shrinkwrap-impl-base</artifactId>
|
|
||||||
<version>1.0.0-alpha-3</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>jclouds-scriptbuilder</artifactId>
|
<artifactId>jclouds-scriptbuilder</artifactId>
|
||||||
|
|
|
@ -22,4 +22,4 @@
|
||||||
- ex. curl http://jclouds.rimuhosting.com/maven2/snapshots/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-20091215.023231-1-jar-with-dependencies.jar >jclouds-antcontrib-all.jar
|
- ex. curl http://jclouds.rimuhosting.com/maven2/snapshots/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-20091215.023231-1-jar-with-dependencies.jar >jclouds-antcontrib-all.jar
|
||||||
2. invoke ant, adding the library above, and passing the properties 'host' 'username' 'keyfile' which corresponds to your remote credentials
|
2. invoke ant, adding the library above, and passing the properties 'host' 'username' 'keyfile' which corresponds to your remote credentials
|
||||||
- ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa
|
- ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa
|
||||||
- ex. ant -lib jclouds-antcontrib-all.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa
|
- ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=localhost -Dusername=$USER -Dkeyfile=$HOME/.ssh/id_dsa
|
||||||
|
|
|
@ -0,0 +1,394 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.tools.ant.taskdefs.optional.ssh;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.types.Resource;
|
||||||
|
import org.apache.tools.ant.types.resources.FileResource;
|
||||||
|
import org.apache.tools.ant.util.FileUtils;
|
||||||
|
import org.apache.tools.ant.util.KeepAliveOutputStream;
|
||||||
|
import org.apache.tools.ant.util.TeeOutputStream;
|
||||||
|
|
||||||
|
import com.jcraft.jsch.ChannelExec;
|
||||||
|
import com.jcraft.jsch.JSchException;
|
||||||
|
import com.jcraft.jsch.Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a command on a remote machine via ssh.
|
||||||
|
* @since Ant 1.6 (created February 2, 2003)
|
||||||
|
*/
|
||||||
|
public class SSHExec extends SSHBase {
|
||||||
|
|
||||||
|
private static final int BUFFER_SIZE = 8192;
|
||||||
|
private static final int RETRY_INTERVAL = 500;
|
||||||
|
|
||||||
|
/** the command to execute via ssh */
|
||||||
|
private String command = null;
|
||||||
|
|
||||||
|
/** units are milliseconds, default is 0=infinite */
|
||||||
|
private long maxwait = 0;
|
||||||
|
|
||||||
|
/** for waiting for the command to finish */
|
||||||
|
private Thread thread = null;
|
||||||
|
|
||||||
|
private String outputProperty = null;
|
||||||
|
private File outputFile = null;
|
||||||
|
private String errorProperty = null;
|
||||||
|
private File errorFile = null;
|
||||||
|
private String resultProperty;
|
||||||
|
private boolean append = false;
|
||||||
|
|
||||||
|
private Resource commandResource = null;
|
||||||
|
|
||||||
|
private static final String TIMEOUT_MESSAGE =
|
||||||
|
"Timeout period exceeded, connection dropped.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for SSHExecTask.
|
||||||
|
*/
|
||||||
|
public SSHExec() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the command to execute on the remote host.
|
||||||
|
*
|
||||||
|
* @param command The new command value
|
||||||
|
*/
|
||||||
|
public void setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a commandResource from a file
|
||||||
|
* @param f the value to use.
|
||||||
|
* @since Ant 1.7.1
|
||||||
|
*/
|
||||||
|
public void setCommandResource(String f) {
|
||||||
|
this.commandResource = new FileResource(new File(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection can be dropped after a specified number of
|
||||||
|
* milliseconds. This is sometimes useful when a connection may be
|
||||||
|
* flaky. Default is 0, which means "wait forever".
|
||||||
|
*
|
||||||
|
* @param timeout The new timeout value in seconds
|
||||||
|
*/
|
||||||
|
public void setTimeout(long timeout) {
|
||||||
|
maxwait = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If used, stores the output of the command to the given file.
|
||||||
|
*
|
||||||
|
* @param output The file to write to.
|
||||||
|
*/
|
||||||
|
public void setOutput(File output) {
|
||||||
|
outputFile = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If used, stores the error of the command to the given file.
|
||||||
|
*
|
||||||
|
* @param error The file to write to.
|
||||||
|
*/
|
||||||
|
public void setError(File error) {
|
||||||
|
this.errorFile = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the output is appended to the file given in
|
||||||
|
* <code>setOutput</code>. Default is false, that is, overwrite
|
||||||
|
* the file.
|
||||||
|
*
|
||||||
|
* @param append True to append to an existing file, false to overwrite.
|
||||||
|
*/
|
||||||
|
public void setAppend(boolean append) {
|
||||||
|
this.append = append;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, the output of the command will be stored in the given property.
|
||||||
|
*
|
||||||
|
* @param property The name of the property in which the command output
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
public void setOutputproperty(String property) {
|
||||||
|
outputProperty = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the property name whose value should be set to the error of
|
||||||
|
* the process.
|
||||||
|
*
|
||||||
|
* @param property The name of a property in which the standard error of
|
||||||
|
* the command should be stored.
|
||||||
|
*/
|
||||||
|
public void setErrorproperty(String property) {
|
||||||
|
errorProperty = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the property in which the return code of the
|
||||||
|
* command should be stored. Only of interest if failonerror=false.
|
||||||
|
*
|
||||||
|
* @param resultProperty name of property.
|
||||||
|
*
|
||||||
|
* @since Ant 1.6
|
||||||
|
*/
|
||||||
|
public void setResultProperty(String resultProperty) {
|
||||||
|
this.resultProperty = resultProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the command on the remote host.
|
||||||
|
*
|
||||||
|
* @exception BuildException Most likely a network error or bad parameter.
|
||||||
|
*/
|
||||||
|
public void execute() throws BuildException {
|
||||||
|
if (getHost() == null) {
|
||||||
|
throw new BuildException("Host is required.");
|
||||||
|
}
|
||||||
|
if (getUserInfo().getName() == null) {
|
||||||
|
throw new BuildException("Username is required.");
|
||||||
|
}
|
||||||
|
if (getUserInfo().getKeyfile() == null
|
||||||
|
&& getUserInfo().getPassword() == null) {
|
||||||
|
throw new BuildException("Password or Keyfile is required.");
|
||||||
|
}
|
||||||
|
if (command == null && commandResource == null) {
|
||||||
|
throw new BuildException("Command or commandResource is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Session session = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
session = openSession();
|
||||||
|
/* called once */
|
||||||
|
if (command != null) {
|
||||||
|
log("cmd : " + command, Project.MSG_INFO);
|
||||||
|
ExecResponse response = executeCommand(session, command);
|
||||||
|
if (outputProperty != null) {
|
||||||
|
getProject().setNewProperty(outputProperty, response.getOutput());
|
||||||
|
}
|
||||||
|
if (errorProperty != null) {
|
||||||
|
getProject().setNewProperty(outputProperty, response.getError());
|
||||||
|
}
|
||||||
|
if (resultProperty != null) {
|
||||||
|
getProject().setNewProperty(resultProperty, response.getCode()+"");
|
||||||
|
}
|
||||||
|
} else { // read command resource and execute for each command
|
||||||
|
try {
|
||||||
|
BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(commandResource.getInputStream()));
|
||||||
|
String cmd;
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
StringBuilder error = new StringBuilder();
|
||||||
|
int lastCode = -1;
|
||||||
|
while ((cmd = br.readLine()) != null) {
|
||||||
|
log("cmd : " + cmd, Project.MSG_INFO);
|
||||||
|
ExecResponse response = executeCommand(session, cmd);
|
||||||
|
output.append(response.getOutput());
|
||||||
|
error.append(response.getError());
|
||||||
|
lastCode = response.getCode();
|
||||||
|
}
|
||||||
|
if (outputProperty != null) {
|
||||||
|
getProject().setNewProperty(outputProperty, output.toString());
|
||||||
|
}
|
||||||
|
if (errorProperty != null) {
|
||||||
|
getProject().setNewProperty(outputProperty, error.toString());
|
||||||
|
}
|
||||||
|
if (resultProperty != null) {
|
||||||
|
getProject().setNewProperty(resultProperty, lastCode+"");
|
||||||
|
}
|
||||||
|
FileUtils.close(br);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JSchException e) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
} finally {
|
||||||
|
if (session != null && session.isConnected()) {
|
||||||
|
session.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class ExecResponse {
|
||||||
|
|
||||||
|
private final String output;
|
||||||
|
private final String error;
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
public ExecResponse(String output, String error, int code) {
|
||||||
|
this.output = output;
|
||||||
|
this.error = error;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutput() {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecResponse executeCommand(Session session, String cmd)
|
||||||
|
throws BuildException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
|
||||||
|
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||||
|
TeeOutputStream teeErr = new TeeOutputStream(err, new KeepAliveOutputStream(System.err));
|
||||||
|
int ec = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ChannelExec channel;
|
||||||
|
session.setTimeout((int) maxwait);
|
||||||
|
/* execute the command */
|
||||||
|
channel = (ChannelExec) session.openChannel("exec");
|
||||||
|
channel.setCommand(cmd);
|
||||||
|
channel.setOutputStream(tee);
|
||||||
|
channel.setExtOutputStream(tee);
|
||||||
|
channel.setErrStream(teeErr);
|
||||||
|
channel.connect();
|
||||||
|
// wait for it to finish
|
||||||
|
thread =
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
while (!channel.isClosed()) {
|
||||||
|
if (thread == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sleep(RETRY_INTERVAL);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
thread.start();
|
||||||
|
thread.join(maxwait);
|
||||||
|
|
||||||
|
if (thread.isAlive()) {
|
||||||
|
// ran out of time
|
||||||
|
thread = null;
|
||||||
|
if (getFailonerror()) {
|
||||||
|
throw new BuildException(TIMEOUT_MESSAGE);
|
||||||
|
} else {
|
||||||
|
log(TIMEOUT_MESSAGE, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//success
|
||||||
|
if (outputFile != null) {
|
||||||
|
writeToFile(out.toString(), append, outputFile);
|
||||||
|
}
|
||||||
|
if (errorFile != null) {
|
||||||
|
writeToFile(err.toString(), append, errorFile);
|
||||||
|
}
|
||||||
|
// this is the wrong test if the remote OS is OpenVMS,
|
||||||
|
// but there doesn't seem to be a way to detect it.
|
||||||
|
ec = channel.getExitStatus();
|
||||||
|
if (ec != 0) {
|
||||||
|
String msg = "Remote command failed with exit status " + ec;
|
||||||
|
if (getFailonerror()) {
|
||||||
|
throw new BuildException(msg);
|
||||||
|
} else {
|
||||||
|
log(msg, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (BuildException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (JSchException e) {
|
||||||
|
if (e.getMessage().indexOf("session is down") >= 0) {
|
||||||
|
if (getFailonerror()) {
|
||||||
|
throw new BuildException(TIMEOUT_MESSAGE, e);
|
||||||
|
} else {
|
||||||
|
log(TIMEOUT_MESSAGE, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (getFailonerror()) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
} else {
|
||||||
|
log("Caught exception: " + e.getMessage(),
|
||||||
|
Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (getFailonerror()) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
} else {
|
||||||
|
log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ExecResponse(out.toString(), err.toString(), ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a string to a file. If destination file exists, it may be
|
||||||
|
* overwritten depending on the "append" value.
|
||||||
|
*
|
||||||
|
* @param from string to write
|
||||||
|
* @param to file to write to
|
||||||
|
* @param append if true, append to existing file, else overwrite
|
||||||
|
* @exception Exception most likely an IOException
|
||||||
|
*/
|
||||||
|
private void writeToFile(String from, boolean append, File to)
|
||||||
|
throws IOException {
|
||||||
|
FileWriter out = null;
|
||||||
|
try {
|
||||||
|
out = new FileWriter(to.getAbsolutePath(), append);
|
||||||
|
StringReader in = new StringReader(from);
|
||||||
|
char[] buffer = new char[BUFFER_SIZE];
|
||||||
|
int bytesRead;
|
||||||
|
while (true) {
|
||||||
|
bytesRead = in.read(buffer);
|
||||||
|
if (bytesRead == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,324 +21,201 @@ package org.jclouds.tools.ant;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.security.SecureRandom;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
import org.apache.tools.ant.BuildException;
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.Location;
|
||||||
import org.apache.tools.ant.Project;
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.Target;
|
||||||
import org.apache.tools.ant.Task;
|
import org.apache.tools.ant.Task;
|
||||||
import org.apache.tools.ant.taskdefs.Java;
|
import org.apache.tools.ant.taskdefs.Java;
|
||||||
|
import org.apache.tools.ant.taskdefs.optional.ssh.SSHExec;
|
||||||
import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo;
|
import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo;
|
||||||
|
import org.apache.tools.ant.taskdefs.optional.ssh.Scp;
|
||||||
import org.apache.tools.ant.types.CommandlineJava;
|
import org.apache.tools.ant.types.CommandlineJava;
|
||||||
import org.apache.tools.ant.types.Environment;
|
import org.apache.tools.ant.types.Environment;
|
||||||
import org.apache.tools.ant.util.KeepAliveOutputStream;
|
import org.apache.tools.ant.types.FileSet;
|
||||||
import org.apache.tools.ant.util.TeeOutputStream;
|
import org.apache.tools.ant.types.Path;
|
||||||
import org.jboss.shrinkwrap.api.Archives;
|
|
||||||
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
|
|
||||||
import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
|
|
||||||
import org.jboss.shrinkwrap.api.importer.ZipImporter;
|
|
||||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
|
||||||
import org.jclouds.scriptbuilder.domain.OsFamily;
|
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
import org.jclouds.scriptbuilder.domain.StatementList;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.io.Closeables;
|
|
||||||
import com.jcraft.jsch.ChannelExec;
|
|
||||||
import com.jcraft.jsch.ChannelSftp;
|
|
||||||
import com.jcraft.jsch.JSch;
|
|
||||||
import com.jcraft.jsch.JSchException;
|
|
||||||
import com.jcraft.jsch.Session;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ported from Jsch SSHExec task.
|
* Version of the Java task that executes over ssh.
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class JavaOverSsh extends Java {
|
public class JavaOverSsh extends Java {
|
||||||
/** Default listen port for SSH daemon */
|
private final SSHExec exec;
|
||||||
private static final int SSH_PORT = 22;
|
private final Scp scp;
|
||||||
|
private final SSHUserInfo userInfo;
|
||||||
|
|
||||||
private String jvm = "/usr/bin/java";
|
private String jvm = "/usr/bin/java";
|
||||||
private File localDirectory;
|
private File localDirectory;
|
||||||
private File remoteDirectory;
|
private File remoteDirectory;
|
||||||
private Environment env = new Environment();
|
private Environment env = new Environment();
|
||||||
private String host;
|
|
||||||
private String knownHosts;
|
|
||||||
private int port = SSH_PORT;
|
|
||||||
private SSHUserInfo userInfo = new SSHUserInfo();
|
|
||||||
private OsFamily osFamily = OsFamily.UNIX;
|
private OsFamily osFamily = OsFamily.UNIX;
|
||||||
|
|
||||||
/** units are milliseconds, default is 0=infinite */
|
|
||||||
private long maxwait = 0;
|
|
||||||
|
|
||||||
/** for waiting for the command to finish */
|
|
||||||
private Thread watchDog = null;
|
|
||||||
private File outputFile;
|
|
||||||
private String outputProperty;
|
|
||||||
private String resultProperty;
|
|
||||||
private File errorFile;
|
private File errorFile;
|
||||||
private String errorProperty;
|
private String errorProperty;
|
||||||
|
private File outputFile;
|
||||||
|
private String outputProperty;
|
||||||
private boolean append;
|
private boolean append;
|
||||||
|
|
||||||
private static final String TIMEOUT_MESSAGE = "Timeout period exceeded, connection dropped.";
|
|
||||||
|
|
||||||
public JavaOverSsh() {
|
public JavaOverSsh() {
|
||||||
super();
|
super();
|
||||||
setFork(true);
|
setFork(true);
|
||||||
|
exec = new SSHExec();
|
||||||
|
scp = new Scp();
|
||||||
|
userInfo = new SSHUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaOverSsh(Task owner) {
|
public JavaOverSsh(Task owner) {
|
||||||
super(owner);
|
this();
|
||||||
setFork(true);
|
bindToOwner(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int executeJava() throws BuildException {
|
public int executeJava() throws BuildException {
|
||||||
String command = convertJavaToScript(getCommandLine());
|
|
||||||
|
|
||||||
InputStream classpathJar = (getCommandLine().getClasspath() != null) ? makeClasspathJarOrNull(getCommandLine()
|
|
||||||
.getClasspath().list())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
InputStream bootClasspathJar = (getCommandLine().getBootclasspath() != null) ? makeClasspathJarOrNull(getCommandLine()
|
|
||||||
.getBootclasspath().list())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
InputStream currentDirectoryZip = Archives.create("cwd.zip", ZipExporter.class).as(
|
|
||||||
ExplodedImporter.class).importDirectory(localDirectory).as(ZipExporter.class)
|
|
||||||
.exportZip();
|
|
||||||
|
|
||||||
if (getHost() == null) {
|
|
||||||
throw new BuildException("Host is required.");
|
|
||||||
}
|
|
||||||
if (getUserInfo().getName() == null) {
|
|
||||||
throw new BuildException("Username is required.");
|
|
||||||
}
|
|
||||||
if (getUserInfo().getKeyfile() == null && getUserInfo().getPassword() == null) {
|
|
||||||
throw new BuildException("Password or Keyfile is required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = null;
|
|
||||||
try {
|
|
||||||
// execute the command
|
|
||||||
session = openSession();
|
|
||||||
session.setTimeout((int) maxwait);
|
|
||||||
ChannelSftp sftp = null;
|
|
||||||
sftp = (ChannelSftp) session.openChannel("sftp");
|
|
||||||
sftp.connect();
|
|
||||||
sftp.put(currentDirectoryZip, remoteDirectory + "/cwd.zip");
|
|
||||||
Closeables.closeQuietly(currentDirectoryZip);
|
|
||||||
|
|
||||||
if (classpathJar != null || bootClasspathJar != null) {
|
|
||||||
if (classpathJar != null) {
|
|
||||||
sftp.put(classpathJar, remoteDirectory + "/classpath.jar");
|
|
||||||
Closeables.closeQuietly(classpathJar);
|
|
||||||
}
|
|
||||||
if (bootClasspathJar != null) {
|
|
||||||
sftp.put(classpathJar, remoteDirectory + "/boot-classpath.jar");
|
|
||||||
Closeables.closeQuietly(classpathJar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final ChannelExec channel = (ChannelExec) session.openChannel("exec");
|
|
||||||
channel.setCommand(command);
|
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
TeeOutputStream teeOut = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
|
|
||||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
|
||||||
TeeOutputStream teeErr = new TeeOutputStream(err, new KeepAliveOutputStream(System.err));
|
|
||||||
|
|
||||||
channel.setOutputStream(teeOut);
|
|
||||||
channel.setExtOutputStream(teeOut);
|
|
||||||
channel.setErrStream(teeErr);
|
|
||||||
|
|
||||||
channel.connect();
|
|
||||||
|
|
||||||
// wait for it to finish
|
|
||||||
watchDog = new Thread() {
|
|
||||||
public void run() {
|
|
||||||
while (!channel.isEOF()) {
|
|
||||||
if (watchDog == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
sleep(500);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
watchDog.start();
|
|
||||||
watchDog.join(maxwait);
|
|
||||||
|
|
||||||
if (watchDog.isAlive()) {
|
|
||||||
// ran out of time
|
|
||||||
|
|
||||||
throw new BuildException(TIMEOUT_MESSAGE);
|
|
||||||
} else {
|
|
||||||
// completed successfully
|
|
||||||
return writeOutputAndReturnExitStatus(channel, out, err);
|
|
||||||
}
|
|
||||||
} catch (BuildException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (JSchException e) {
|
|
||||||
if (e.getMessage().indexOf("session is down") >= 0) {
|
|
||||||
throw new BuildException(TIMEOUT_MESSAGE, e);
|
|
||||||
} else {
|
|
||||||
throw new BuildException(e);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new BuildException(e);
|
|
||||||
} finally {
|
|
||||||
if (session != null && session.isConnected()) {
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream makeClasspathJarOrNull(String... paths) {
|
|
||||||
if (paths != null && paths.length > 0) {
|
|
||||||
JavaArchive classpathArchive = Archives.create("classpath.jar", JavaArchive.class);
|
|
||||||
for (String path : paths) {
|
|
||||||
File file = new File(path);
|
|
||||||
if (file.exists()) {
|
|
||||||
if (file.isFile()) {
|
|
||||||
try {
|
|
||||||
classpathArchive.as(ZipImporter.class).importZip(
|
|
||||||
new ZipFile(file.getAbsolutePath()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new BuildException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
classpathArchive.as(ExplodedImporter.class).importDirectory(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return classpathArchive.as(ZipExporter.class).exportZip();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int writeOutputAndReturnExitStatus(final ChannelExec channel, ByteArrayOutputStream out,
|
|
||||||
ByteArrayOutputStream err) throws IOException {
|
|
||||||
if (outputProperty != null) {
|
|
||||||
getProject().setProperty(outputProperty, out.toString());
|
|
||||||
}
|
|
||||||
if (outputFile != null) {
|
|
||||||
writeToFile(err.toString(), append, outputFile);
|
|
||||||
}
|
|
||||||
if (errorProperty != null) {
|
|
||||||
getProject().setProperty(errorProperty, err.toString());
|
|
||||||
}
|
|
||||||
if (errorFile != null) {
|
|
||||||
writeToFile(out.toString(), append, errorFile);
|
|
||||||
}
|
|
||||||
if (resultProperty != null) {
|
|
||||||
getProject().setProperty(resultProperty, channel.getExitStatus() + "");
|
|
||||||
}
|
|
||||||
return channel.getExitStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a string to a file. If destination file exists, it may be overwritten depending on the
|
|
||||||
* "append" value.
|
|
||||||
*
|
|
||||||
* @param from
|
|
||||||
* string to write
|
|
||||||
* @param to
|
|
||||||
* file to write to
|
|
||||||
* @param append
|
|
||||||
* if true, append to existing file, else overwrite
|
|
||||||
* @exception Exception
|
|
||||||
* most likely an IOException
|
|
||||||
*/
|
|
||||||
private void writeToFile(String from, boolean append, File to) throws IOException {
|
|
||||||
FileWriter out = null;
|
|
||||||
try {
|
|
||||||
out = new FileWriter(to.getAbsolutePath(), append);
|
|
||||||
StringReader in = new StringReader(from);
|
|
||||||
char[] buffer = new char[8192];
|
|
||||||
int bytesRead;
|
|
||||||
while (true) {
|
|
||||||
bytesRead = in.read(buffer);
|
|
||||||
if (bytesRead == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
out.flush();
|
|
||||||
} finally {
|
|
||||||
if (out != null) {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String convertJavaToScript(CommandlineJava commandLine) {
|
|
||||||
checkNotNull(jvm, "jvm must be set");
|
checkNotNull(jvm, "jvm must be set");
|
||||||
checkNotNull(localDirectory, "dir must be set");
|
|
||||||
checkNotNull(remoteDirectory, "remotedir must be set");
|
checkNotNull(remoteDirectory, "remotedir must be set");
|
||||||
|
// must copy the files over first as we are changing the system properties based on this.
|
||||||
|
|
||||||
|
if (localDirectory != null) {
|
||||||
|
FileSet cwd = new FileSet();
|
||||||
|
cwd.setDir(localDirectory);
|
||||||
|
mkdirAndCopyTo(remoteDirectory.getAbsolutePath(), ImmutableList.of(cwd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCommandLine().getClasspath() != null) {
|
||||||
|
copyPathTo(getCommandLine().getClasspath(), remoteDirectory.getAbsolutePath()
|
||||||
|
+ "/classpath");
|
||||||
|
}
|
||||||
|
if (getCommandLine().getBootclasspath() != null) {
|
||||||
|
copyPathTo(getCommandLine().getBootclasspath(), remoteDirectory.getAbsolutePath()
|
||||||
|
+ "/bootclasspath");
|
||||||
|
}
|
||||||
|
|
||||||
|
String command = convertJavaToScriptNormalizingPaths(getCommandLine());
|
||||||
|
|
||||||
|
String random = new SecureRandom().nextInt() + "";
|
||||||
|
exec.setResultProperty(random);
|
||||||
|
exec.setFailonerror(false);
|
||||||
|
exec.setCommand(command);
|
||||||
|
exec.setError(errorFile);
|
||||||
|
exec.setErrorproperty(errorProperty);
|
||||||
|
exec.setOutput(outputFile);
|
||||||
|
exec.setOutputproperty(outputProperty);
|
||||||
|
exec.setAppend(append);
|
||||||
|
exec.execute();
|
||||||
|
return Integer.parseInt(getProject().getProperty(random));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
|
||||||
|
scp.init();
|
||||||
|
exec.setCommand(exec("{md} " + destination).render(osFamily));
|
||||||
|
exec.execute();
|
||||||
|
String scpDestination = getScpDir(destination);
|
||||||
|
System.out.println("Sending to: " + scpDestination);
|
||||||
|
for (FileSet set : sets)
|
||||||
|
scp.addFileset(set);
|
||||||
|
scp.setTodir(scpDestination);
|
||||||
|
scp.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getScpDir(String path) {
|
||||||
|
return String.format("%s:%s@%s:%s", userInfo.getName(),
|
||||||
|
userInfo.getKeyfile() == null ? userInfo.getPassword() : userInfo.getPassphrase(),
|
||||||
|
scp.getHost(), path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(Path path, String prefix,
|
||||||
|
StringBuilder destination) {
|
||||||
|
if (path == null)
|
||||||
|
return;
|
||||||
|
String[] paths = path.list();
|
||||||
|
if (paths != null && paths.length > 0) {
|
||||||
|
for (int i = 0; i < paths.length; i++) {
|
||||||
|
File file = new File(paths[i]);
|
||||||
|
if (file.exists()) {
|
||||||
|
// directories are flattened under the prefix anyway, so there's no need to add them
|
||||||
|
// to the path
|
||||||
|
if (file.isFile())
|
||||||
|
destination.append("{ps}").append(file.getName());
|
||||||
|
} else {
|
||||||
|
// if the file doesn't exist, it is probably a "forward reference" to something that
|
||||||
|
// is already on the remote machine
|
||||||
|
destination.append("{ps}").append(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyPathTo(Path path, String destination) {
|
||||||
|
List<FileSet> filesets = Lists.newArrayList();
|
||||||
|
if (path.list() != null && path.list().length > 0) {
|
||||||
|
for (String filepath : path.list()) {
|
||||||
|
File file = new File(filepath);
|
||||||
|
if (file.exists()) {
|
||||||
|
FileSet fileset = new FileSet();
|
||||||
|
if (file.isFile()) {
|
||||||
|
fileset.setFile(file);
|
||||||
|
} else {
|
||||||
|
fileset.setDir(file);
|
||||||
|
}
|
||||||
|
filesets.add(fileset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mkdirAndCopyTo(destination, filesets);
|
||||||
|
}
|
||||||
|
|
||||||
|
String convertJavaToScriptNormalizingPaths(CommandlineJava commandLine) {
|
||||||
List<Statement> statements = Lists.newArrayList();
|
List<Statement> statements = Lists.newArrayList();
|
||||||
String[] environment = env.getVariables();
|
String[] environment = env.getVariables();
|
||||||
if (environment != null) {
|
if (environment != null) {
|
||||||
for (int i = 0; i < environment.length; i++) {
|
for (int i = 0; i < environment.length; i++) {
|
||||||
log("Setting environment variable: " + environment[i], Project.MSG_VERBOSE);
|
log("Setting environment variable: " + environment[i], Project.MSG_VERBOSE);
|
||||||
statements.add(exec("{export} " + environment[i]));
|
String[] keyValue = environment[i].split("=");
|
||||||
|
statements.add(exec(String.format("{export} %s={vq}%s{vq}", keyValue[0], keyValue[1])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statements.add(exec("{cd} " + remoteDirectory));
|
statements.add(exec("{cd} " + remoteDirectory));
|
||||||
statements.add(exec("jar -xf cwd.zip"));
|
|
||||||
|
|
||||||
StringBuilder commandBuilder = new StringBuilder(jvm);
|
StringBuilder commandBuilder = new StringBuilder(jvm);
|
||||||
if (commandLine.getBootclasspath() != null
|
if (getCommandLine().getBootclasspath() != null) {
|
||||||
&& commandLine.getBootclasspath().list().length > 0) {
|
commandBuilder.append(" -Xbootclasspath:bootclasspath");
|
||||||
commandBuilder.append(" -Xbootclasspath:boot-classpath.jar");
|
resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getBootclasspath(),
|
||||||
|
"bootclasspath", commandBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commandLine.getVmCommand().getArguments() != null
|
if (commandLine.getVmCommand().getArguments() != null
|
||||||
&& commandLine.getVmCommand().getArguments().length > 0) {
|
&& commandLine.getVmCommand().getArguments().length > 0) {
|
||||||
commandBuilder.append(" ");
|
commandBuilder.append(" ").append(
|
||||||
String[] variables = commandLine.getVmCommand().getArguments();
|
Joiner.on(' ').join(commandLine.getVmCommand().getArguments()));
|
||||||
for (int i = 0; i < variables.length; i++) {
|
|
||||||
commandBuilder.append(variables[i]);
|
|
||||||
if (i + 1 < variables.length)
|
|
||||||
commandBuilder.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (commandLine.getClasspath() != null && commandLine.getClasspath().list().length > 0) {
|
|
||||||
commandBuilder.append(" -cp classpath.jar");
|
|
||||||
}
|
}
|
||||||
|
commandBuilder.append(" -cp classpath");
|
||||||
|
resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getClasspath(),
|
||||||
|
"classpath", commandBuilder);
|
||||||
|
|
||||||
if (commandLine.getSystemProperties() != null
|
if (commandLine.getSystemProperties() != null
|
||||||
&& commandLine.getSystemProperties().getVariables() != null
|
&& commandLine.getSystemProperties().getVariables() != null
|
||||||
&& commandLine.getSystemProperties().getVariables().length > 0) {
|
&& commandLine.getSystemProperties().getVariables().length > 0) {
|
||||||
commandBuilder.append(" ");
|
commandBuilder.append(" ").append(
|
||||||
String[] variables = commandLine.getSystemProperties().getVariables();
|
Joiner.on(' ').join(commandLine.getSystemProperties().getVariables()));
|
||||||
for (int i = 0; i < variables.length; i++) {
|
|
||||||
commandBuilder.append(variables[i]);
|
|
||||||
if (i + 1 < variables.length)
|
|
||||||
commandBuilder.append(" ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commandBuilder.append(" ").append(commandLine.getClassname());
|
commandBuilder.append(" ").append(commandLine.getClassname());
|
||||||
|
|
||||||
if (commandLine.getJavaCommand().getArguments() != null
|
if (commandLine.getJavaCommand().getArguments() != null
|
||||||
&& commandLine.getJavaCommand().getArguments().length > 0) {
|
&& commandLine.getJavaCommand().getArguments().length > 0) {
|
||||||
commandBuilder.append(" ");
|
commandBuilder.append(" ").append(
|
||||||
String[] variables = commandLine.getJavaCommand().getArguments();
|
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
|
||||||
for (int i = 0; i < variables.length; i++) {
|
|
||||||
commandBuilder.append(variables[i]);
|
|
||||||
if (i + 1 < variables.length)
|
|
||||||
commandBuilder.append(" ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
statements.add(exec(commandBuilder.toString()));
|
statements.add(exec(commandBuilder.toString()));
|
||||||
|
|
||||||
|
@ -351,6 +228,10 @@ public class JavaOverSsh extends Java {
|
||||||
env.addVariable(var);
|
env.addVariable(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that if the {@code dir} property is set, this will be copied recursively to the remote
|
||||||
|
* host.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setDir(File localDir) {
|
public void setDir(File localDir) {
|
||||||
this.localDirectory = checkNotNull(localDir, "dir");
|
this.localDirectory = checkNotNull(localDir, "dir");
|
||||||
|
@ -378,7 +259,8 @@ public class JavaOverSsh extends Java {
|
||||||
* The new host value
|
* The new host value
|
||||||
*/
|
*/
|
||||||
public void setHost(String host) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
exec.setHost(host);
|
||||||
|
scp.setHost(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -387,7 +269,7 @@ public class JavaOverSsh extends Java {
|
||||||
* @return the host
|
* @return the host
|
||||||
*/
|
*/
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return exec.getHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -397,6 +279,8 @@ public class JavaOverSsh extends Java {
|
||||||
* The new username value
|
* The new username value
|
||||||
*/
|
*/
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
|
exec.setUsername(username);
|
||||||
|
scp.setUsername(username);
|
||||||
userInfo.setName(username);
|
userInfo.setName(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +291,8 @@ public class JavaOverSsh extends Java {
|
||||||
* The new password value
|
* The new password value
|
||||||
*/
|
*/
|
||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
|
exec.setPassword(password);
|
||||||
|
scp.setPassword(password);
|
||||||
userInfo.setPassword(password);
|
userInfo.setPassword(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +303,11 @@ public class JavaOverSsh extends Java {
|
||||||
* The new keyfile value
|
* The new keyfile value
|
||||||
*/
|
*/
|
||||||
public void setKeyfile(String keyfile) {
|
public void setKeyfile(String keyfile) {
|
||||||
|
exec.setKeyfile(keyfile);
|
||||||
|
scp.setKeyfile(keyfile);
|
||||||
userInfo.setKeyfile(keyfile);
|
userInfo.setKeyfile(keyfile);
|
||||||
|
if (userInfo.getPassphrase() == null)
|
||||||
|
userInfo.setPassphrase("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -427,6 +317,8 @@ public class JavaOverSsh extends Java {
|
||||||
* The new passphrase value
|
* The new passphrase value
|
||||||
*/
|
*/
|
||||||
public void setPassphrase(String passphrase) {
|
public void setPassphrase(String passphrase) {
|
||||||
|
exec.setPassphrase(passphrase);
|
||||||
|
scp.setPassphrase(passphrase);
|
||||||
userInfo.setPassphrase(passphrase);
|
userInfo.setPassphrase(passphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +331,8 @@ public class JavaOverSsh extends Java {
|
||||||
* a path to the known hosts file.
|
* a path to the known hosts file.
|
||||||
*/
|
*/
|
||||||
public void setKnownhosts(String knownHosts) {
|
public void setKnownhosts(String knownHosts) {
|
||||||
this.knownHosts = knownHosts;
|
exec.setKnownhosts(knownHosts);
|
||||||
|
scp.setKnownhosts(knownHosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -449,6 +342,8 @@ public class JavaOverSsh extends Java {
|
||||||
* if true trust the identity of unknown hosts.
|
* if true trust the identity of unknown hosts.
|
||||||
*/
|
*/
|
||||||
public void setTrust(boolean yesOrNo) {
|
public void setTrust(boolean yesOrNo) {
|
||||||
|
exec.setTrust(yesOrNo);
|
||||||
|
scp.setTrust(yesOrNo);
|
||||||
userInfo.setTrust(yesOrNo);
|
userInfo.setTrust(yesOrNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,7 +354,8 @@ public class JavaOverSsh extends Java {
|
||||||
* port number of remote host.
|
* port number of remote host.
|
||||||
*/
|
*/
|
||||||
public void setPort(int port) {
|
public void setPort(int port) {
|
||||||
this.port = port;
|
exec.setPort(port);
|
||||||
|
scp.setPort(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -468,7 +364,7 @@ public class JavaOverSsh extends Java {
|
||||||
* @return the port
|
* @return the port
|
||||||
*/
|
*/
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
return exec.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -479,42 +375,8 @@ public class JavaOverSsh extends Java {
|
||||||
*/
|
*/
|
||||||
public void init() throws BuildException {
|
public void init() throws BuildException {
|
||||||
super.init();
|
super.init();
|
||||||
this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
|
exec.init();
|
||||||
this.port = SSH_PORT;
|
scp.init();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open an ssh seession.
|
|
||||||
*
|
|
||||||
* @return the opened session
|
|
||||||
* @throws JSchException
|
|
||||||
* on error
|
|
||||||
*/
|
|
||||||
protected Session openSession() throws JSchException {
|
|
||||||
JSch jsch = new JSch();
|
|
||||||
if (null != userInfo.getKeyfile()) {
|
|
||||||
jsch.addIdentity(userInfo.getKeyfile());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userInfo.getTrust() && knownHosts != null) {
|
|
||||||
log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
|
|
||||||
jsch.setKnownHosts(knownHosts);
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = jsch.getSession(userInfo.getName(), host, port);
|
|
||||||
session.setUserInfo(userInfo);
|
|
||||||
log("Connecting to " + host + ":" + port);
|
|
||||||
session.connect();
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user information.
|
|
||||||
*
|
|
||||||
* @return the user information
|
|
||||||
*/
|
|
||||||
protected SSHUserInfo getUserInfo() {
|
|
||||||
return userInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -525,36 +387,85 @@ public class JavaOverSsh extends Java {
|
||||||
* The new timeout value in seconds
|
* The new timeout value in seconds
|
||||||
*/
|
*/
|
||||||
public void setTimeout(long timeout) {
|
public void setTimeout(long timeout) {
|
||||||
maxwait = timeout;
|
exec.setTimeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the verbose flag.
|
||||||
|
*
|
||||||
|
* @param verbose
|
||||||
|
* if true output more verbose logging
|
||||||
|
* @since Ant 1.6.2
|
||||||
|
*/
|
||||||
|
public void setVerbose(boolean verbose) {
|
||||||
|
exec.setVerbose(verbose);
|
||||||
|
scp.setVerbose(verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setError(File out) {
|
public void setError(File error) {
|
||||||
this.errorFile = out;
|
this.errorFile = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setErrorProperty(String errorProp) {
|
public void setErrorProperty(String property) {
|
||||||
this.errorProperty = errorProp;
|
errorProperty = property;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOutput(File out) {
|
public void setOutput(File out) {
|
||||||
this.outputFile = out;
|
outputFile = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOutputproperty(String outputProp) {
|
public void setOutputproperty(String outputProp) {
|
||||||
this.outputProperty = outputProp;
|
outputProperty = outputProp;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResultProperty(String resultProperty) {
|
|
||||||
this.resultProperty = resultProperty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAppend(boolean append) {
|
public void setAppend(boolean append) {
|
||||||
this.append = append;
|
this.append = append;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProject(Project project) {
|
||||||
|
super.setProject(project);
|
||||||
|
exec.setProject(project);
|
||||||
|
scp.setProject(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwningTarget(Target target) {
|
||||||
|
super.setOwningTarget(target);
|
||||||
|
exec.setOwningTarget(target);
|
||||||
|
scp.setOwningTarget(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTaskName(String taskName) {
|
||||||
|
super.setTaskName(taskName);
|
||||||
|
exec.setTaskName(taskName);
|
||||||
|
scp.setTaskName(taskName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDescription(String description) {
|
||||||
|
super.setDescription(description);
|
||||||
|
exec.setDescription(description);
|
||||||
|
scp.setDescription(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLocation(Location location) {
|
||||||
|
super.setLocation(location);
|
||||||
|
exec.setLocation(location);
|
||||||
|
scp.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTaskType(String type) {
|
||||||
|
super.setTaskType(type);
|
||||||
|
exec.setTaskType(type);
|
||||||
|
scp.setTaskType(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,33 +24,39 @@ import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.apache.tools.ant.Project;
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.taskdefs.Java;
|
||||||
import org.apache.tools.ant.types.Environment;
|
import org.apache.tools.ant.types.Environment;
|
||||||
import org.apache.tools.ant.types.Path;
|
import org.apache.tools.ant.types.Path;
|
||||||
import org.apache.tools.ant.types.Environment.Variable;
|
import org.apache.tools.ant.types.Environment.Variable;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "unit", testName = "jclouds.JavaOverSshTest")
|
@Test(groups = "unit", testName = "jclouds.JavaOverSshTest")
|
||||||
public class JavaOverSshTest {
|
public class JavaOverSshTest {
|
||||||
|
public static final Entry<String, String> LAST_ENV = Iterables.getLast(System.getenv()
|
||||||
|
.entrySet());
|
||||||
|
|
||||||
|
// TODO, this test will break in windows
|
||||||
public void testFull() throws SecurityException, NoSuchMethodException {
|
public void testFull() throws SecurityException, NoSuchMethodException {
|
||||||
JavaOverSsh task = createTask();
|
JavaOverSsh task = makeJavaOverSsh();
|
||||||
assertEquals(
|
String expected = String
|
||||||
String
|
.format(
|
||||||
.format(
|
"export %s=\"%s\"%ncd /tmp/foo\n%s -Xms16m -Xmx32m -cp classpath -Dfooble=baz -Dfoo=bar org.jclouds.tools.ant.TestClass %s hello world\n",
|
||||||
"cd /tmp/foo\njar -xf cwd.zip\n%s -Xms256 -cp classpath.jar -Dfooble=baz -Dfoo=bar org.jclouds.tools.ant.TestClass hello world\n",
|
LAST_ENV.getKey(), LAST_ENV.getValue(), System.getProperty("java.home")
|
||||||
System.getProperty("java.home") + "/bin/java", System
|
+ "/bin/java", LAST_ENV.getKey());
|
||||||
.getProperty("user.dir")), task.convertJavaToScript(task
|
assertEquals(task.convertJavaToScriptNormalizingPaths(task.getCommandLine()), expected);
|
||||||
.getCommandLine()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JavaOverSsh createTask() {
|
private Java populateTask(Java task) {
|
||||||
Project p = new Project();
|
Project p = new Project();
|
||||||
JavaOverSsh task = new JavaOverSsh();
|
|
||||||
task.setProject(p);
|
task.setProject(p);
|
||||||
task.setClassname(TestClass.class.getName());
|
task.setClassname(TestClass.class.getName());
|
||||||
task.createClasspath().add(new Path(p, "target/test-classes"));
|
task.createClasspath().add(new Path(p, "target/test-classes"));
|
||||||
|
@ -62,20 +68,43 @@ public class JavaOverSshTest {
|
||||||
Variable prop2 = new Environment.Variable();
|
Variable prop2 = new Environment.Variable();
|
||||||
prop2.setKey("foo");
|
prop2.setKey("foo");
|
||||||
prop2.setValue("bar");
|
prop2.setValue("bar");
|
||||||
|
|
||||||
task.addSysproperty(prop2);
|
task.addSysproperty(prop2);
|
||||||
task.createJvmarg().setValue("-Xms256");
|
task.createJvmarg().setValue("-Xms16m");
|
||||||
|
task.createJvmarg().setValue("-Xmx32m");
|
||||||
|
Variable env = new Environment.Variable();
|
||||||
|
env.setKey(LAST_ENV.getKey());
|
||||||
|
env.setValue(LAST_ENV.getValue());
|
||||||
|
task.addEnv(env);
|
||||||
|
task.createArg().setValue(env.getKey());
|
||||||
task.createArg().setValue("hello");
|
task.createArg().setValue("hello");
|
||||||
task.createArg().setValue("world");
|
task.createArg().setValue("world");
|
||||||
task.setDir(new File(System.getProperty("user.dir")));
|
task.setDir(new File(System.getProperty("user.dir")));
|
||||||
task.setRemotedir(new File("/tmp/foo"));
|
|
||||||
task.setFork(true);
|
task.setFork(true);
|
||||||
task.setJvm(System.getProperty("java.home") + "/bin/java");
|
task.setJvm(System.getProperty("java.home") + "/bin/java");
|
||||||
|
task.setOutputproperty("out");
|
||||||
|
task.setErrorProperty("err");
|
||||||
|
task.setResultProperty("result");
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(enabled = false, groups = { "live" })
|
@Test(enabled = false, groups = { "live" })
|
||||||
public void testSsh() throws NumberFormatException, FileNotFoundException, IOException {
|
public void testSsh() throws NumberFormatException, FileNotFoundException, IOException {
|
||||||
|
Java java = makeJava();
|
||||||
|
java.execute();
|
||||||
|
|
||||||
|
JavaOverSsh javaOverSsh = makeJavaOverSsh();
|
||||||
|
addDestinationTo(javaOverSsh);
|
||||||
|
javaOverSsh.execute();
|
||||||
|
|
||||||
|
assertEquals(javaOverSsh.getProject().getProperty("out"), javaOverSsh.getProject()
|
||||||
|
.getProperty("out"));
|
||||||
|
assertEquals(javaOverSsh.getProject().getProperty("err"), javaOverSsh.getProject()
|
||||||
|
.getProperty("err"));
|
||||||
|
assertEquals(javaOverSsh.getProject().getProperty("result"), javaOverSsh.getProject()
|
||||||
|
.getProperty("result"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDestinationTo(JavaOverSsh javaOverSsh) throws UnknownHostException {
|
||||||
String sshHost = System.getProperty("jclouds.test.ssh.host");
|
String sshHost = System.getProperty("jclouds.test.ssh.host");
|
||||||
String sshPort = System.getProperty("jclouds.test.ssh.port");
|
String sshPort = System.getProperty("jclouds.test.ssh.port");
|
||||||
String sshUser = System.getProperty("jclouds.test.ssh.username");
|
String sshUser = System.getProperty("jclouds.test.ssh.username");
|
||||||
|
@ -85,23 +114,26 @@ public class JavaOverSshTest {
|
||||||
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
|
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
|
||||||
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
|
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
|
||||||
.getLocalHost();
|
.getLocalHost();
|
||||||
|
javaOverSsh.setHost(host.getHostAddress());
|
||||||
JavaOverSsh task = createTask();
|
javaOverSsh.setPort(port);
|
||||||
task.setHost(host.getHostAddress());
|
javaOverSsh.setUsername(sshUser);
|
||||||
task.setPort(port);
|
|
||||||
task.setTrust(true);
|
|
||||||
task.setUsername(sshUser);
|
|
||||||
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
|
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
|
||||||
task.setKeyfile(sshKeyFile);
|
javaOverSsh.setKeyfile(sshKeyFile);
|
||||||
} else {
|
} else {
|
||||||
task.setPassword(sshPass);
|
javaOverSsh.setPassword(sshPass);
|
||||||
}
|
}
|
||||||
task.setOutputproperty("out");
|
}
|
||||||
task.setErrorProperty("err");
|
|
||||||
task.setResultProperty("result");
|
private JavaOverSsh makeJavaOverSsh() {
|
||||||
task.execute();
|
JavaOverSsh task = new JavaOverSsh();
|
||||||
assertEquals(task.getProject().getProperty("out"), "[hello, world]\n");
|
populateTask(task);
|
||||||
assertEquals(task.getProject().getProperty("err"), "err\n");
|
task.setRemotedir(new File("/tmp/foo"));
|
||||||
assertEquals(task.getProject().getProperty("result"), "3");
|
task.setVerbose(true);
|
||||||
|
task.setTrust(true);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Java makeJava() {
|
||||||
|
return populateTask(new Java());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import java.util.Arrays;
|
||||||
|
|
||||||
public class TestClass {
|
public class TestClass {
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
|
System.out.println("env:");
|
||||||
|
System.out.println(System.getenv(args[0]));
|
||||||
File cwd = new File(System.getProperty("user.dir"));
|
File cwd = new File(System.getProperty("user.dir"));
|
||||||
System.out.println("children:");
|
System.out.println("children:");
|
||||||
for (File child : cwd.listFiles())
|
for (File child : cwd.listFiles())
|
||||||
|
|
Loading…
Reference in New Issue