reduced log clutter and hardened code

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2621 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2010-01-09 22:40:46 +00:00
parent 7f5b800470
commit b9de6558d5
5 changed files with 395 additions and 566 deletions

View File

@ -19,7 +19,7 @@
==================================================================== ====================================================================
--> -->
<project name="javassh" default="javassh" basedir="."> <project name="sshjava" default="sshjava" basedir=".">
<description> <description>
simple example build file simple example build file
</description> </description>
@ -67,17 +67,17 @@
<delete dir="${dist}"/> <delete dir="${dist}"/>
</target> </target>
<taskdef name="javassh" classname="org.jclouds.tools.ant.JavaOverSsh"/> <taskdef name="sshjava" classname="org.jclouds.tools.ant.taskdefs.sshjava.SSHJava" />
<target name="javassh" depends="compile" description="remote execute the java command"> <target name="sshjava" depends="compile" description="remote execute the java command">
<echo message="normal java task"/> <echo message="normal java task"/>
<java classname="TestClass" classpath="${build}" dir="${user.dir}" > <java classname="TestClass" classpath="${build}" dir="${user.dir}" >
<arg line="${line}"/> <arg line="${line}"/>
</java> </java>
<echo message="java task over ssh"/> <echo message="java task over ssh"/>
<javassh classname="TestClass" classpath="${build}" dir="${user.dir}" host="${host}" username="${username}" keyfile="${keyfile}" trust="true" remotedir="/tmp/test" > <sshjava classname="TestClass" classpath="${build}" dir="${user.dir}" host="${host}" username="${username}" keyfile="${keyfile}" trust="true" remotebase="/tmp/test" >
<arg line="${line}"/> <arg line="${line}"/>
</javassh> </sshjava>
</target> </target>
</project> </project>

View File

@ -1,394 +0,0 @@
/*
* 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 &quot;wait forever&quot;.
*
* @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();
}
}
}
}

View File

@ -0,0 +1,338 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.tools.ant.taskdefs.sshjava;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
import org.apache.tools.ant.taskdefs.PumpStreamHandler;
import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo;
import org.apache.tools.ant.util.FileUtils;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* Executes a command on a remote machine via ssh.
*
* <p/>
* adapted from SSHBase and SSHExec ant tasks, and Execute from the ant 1.7.1 release.
*
* @author Adrian Cole
*
*/
public class SSHExecute {
private static final int RETRY_INTERVAL = 500;
/** units are milliseconds, default is 0=infinite */
private long maxwait = 0;
private ExecuteStreamHandler streamHandler;
private String host;
private SSHUserInfo userInfo;
private int port = 22;
private Project project;
private String knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
/**
* Creates a new execute object using <code>PumpStreamHandler</code> for stream handling.
*/
public SSHExecute() {
this(new PumpStreamHandler());
}
/**
* Creates a new ssh object.
*
* @param streamHandler
* the stream handler used to handle the input and output streams of the subprocess.
*/
public SSHExecute(ExecuteStreamHandler streamHandler) {
setStreamHandler(streamHandler);
userInfo = new SSHUserInfo();
}
/**
* Set the stream handler to use.
*
* @param streamHandler
* ExecuteStreamHandler.
*/
public void setStreamHandler(ExecuteStreamHandler streamHandler) {
this.streamHandler = streamHandler;
}
/**
* Setting this to true trusts hosts whose identity is unknown.
*
* @param yesOrNo
* if true trust the identity of unknown hosts.
*/
public void setTrust(boolean yesOrNo) {
userInfo.setTrust(yesOrNo);
}
/**
* Used for logging
*/
public void setProject(Project project) {
this.project = project;
}
/**
* Username known to remote host.
*
* @param username
* The new username value
*/
public void setUsername(String username) {
userInfo.setName(username);
}
/**
* Sets the password for the user.
*
* @param password
* The new password value
*/
public void setPassword(String password) {
userInfo.setPassword(password);
}
/**
* Sets the keyfile for the user.
*
* @param keyfile
* The new keyfile value
*/
public void setKeyfile(String keyfile) {
userInfo.setKeyfile(keyfile);
}
/**
* Sets the passphrase for the users key.
*
* @param passphrase
* The new passphrase value
*/
public void setPassphrase(String passphrase) {
userInfo.setPassphrase(passphrase);
}
/**
* Remote host, either DNS name or IP.
*
* @param host
* The new host value
*/
public void setHost(String host) {
this.host = host;
}
/**
* Changes the port used to connect to the remote host.
*
* @param port
* port number of remote host.
*/
public void setPort(int port) {
this.port = port;
}
/**
* 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 &quot;wait forever&quot;.
*
* @param timeout
* The new timeout value in seconds
*/
public void setTimeout(long timeout) {
maxwait = timeout;
}
/**
* Sets the path to the file that has the identities of all known hosts. This is used by SSH
* protocol to validate the identity of the host. The default is
* <i>${user.home}/.ssh/known_hosts</i>.
*
* @param knownHosts
* a path to the known hosts file.
*/
public void setKnownhosts(String knownHosts) {
this.knownHosts = knownHosts;
}
/**
* Execute the command on the remote host.
*
* @param command
* - what to execute on the remote host.
*
* @return return code of the process.
* @throws BuildException
* bad parameter.
* @throws JSchException
* if there's an underlying problem exposed in SSH
* @throws IOException
* if there's a problem attaching streams.
* @throws TimeoutException
* if we exceeded our timeout
*/
public int execute(String command) throws BuildException, JSchException, IOException,
TimeoutException {
if (command == null) {
throw new BuildException("Command is required.");
}
if (host == null) {
throw new BuildException("Host is required.");
}
if (userInfo.getName() == null) {
throw new BuildException("Username is required.");
}
if (userInfo.getKeyfile() == null && userInfo.getPassword() == null) {
throw new BuildException("Password or Keyfile is required.");
}
Session session = null;
try {
session = openSession();
return executeCommand(session, command);
} finally {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
/**
* 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) {
project.log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
jsch.setKnownHosts(knownHosts);
}
Session session = jsch.getSession(userInfo.getName(), host, port);
session.setUserInfo(userInfo);
project.log("Connecting to " + host + ":" + port, Project.MSG_VERBOSE);
session.connect();
return session;
}
/**
*
* FIXME Comment this
*
* @param session
* @param cmd
* @return return code of the process.
* @throws JSchException
* if there's an underlying problem exposed in SSH
* @throws IOException
* if there's a problem attaching streams.
* @throws TimeoutException
* if we exceeded our timeout
*/
private int executeCommand(Session session, String cmd) throws JSchException, IOException,
TimeoutException {
final ChannelExec channel;
session.setTimeout((int) maxwait);
/* execute the command */
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(cmd);
attachStreams(channel);
project.log("executing command: " + cmd, Project.MSG_VERBOSE);
channel.connect();
try {
waitFor(channel);
} finally {
streamHandler.stop();
closeStreams(channel);
}
return channel.getExitStatus();
}
private void attachStreams(final ChannelExec channel) throws IOException {
streamHandler.setProcessInputStream(channel.getOutputStream());
streamHandler.setProcessOutputStream(channel.getInputStream());
streamHandler.setProcessErrorStream(channel.getErrStream());
streamHandler.start();
}
/**
* Close the streams belonging to the given Process.
*
* @param process
* the <code>Process</code>.
* @throws IOException
*/
public static void closeStreams(ChannelExec process) throws IOException {
FileUtils.close(process.getInputStream());
FileUtils.close(process.getOutputStream());
FileUtils.close(process.getErrStream());
}
/**
* @throws TimeoutException
*/
@SuppressWarnings("deprecation")
private void waitFor(final ChannelExec channel) throws TimeoutException {
// wait for it to finish
Thread thread = new Thread() {
public void run() {
while (!channel.isClosed()) {
try {
sleep(RETRY_INTERVAL);
} catch (InterruptedException e) {
// ignored
}
}
}
};
thread.start();
try {
thread.join(maxwait);
} catch (InterruptedException e) {
// ignored
}
if (thread.isAlive()) {
thread.destroy();
throw new TimeoutException("command still running");
}
}
}

View File

@ -25,22 +25,18 @@ import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.TimeoutException;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Location; import org.apache.tools.ant.Location;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Target; 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.taskdefs.optional.ssh.Scp;
import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.CommandlineJava;
@ -60,6 +56,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.jcraft.jsch.JSchException;
/** /**
* Version of the Java task that executes over ssh. * Version of the Java task that executes over ssh.
@ -67,11 +64,9 @@ import com.google.common.collect.Maps;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SSHJava extends Java { public class SSHJava extends Java {
private final SSHExec exec; private final SSHExecute exec;
private final Scp scp; private final Scp scp;
private final SSHUserInfo userInfo; private final SSHUserInfo userInfo;
private String jvm = "/usr/bin/java";
private File localDirectory; private File localDirectory;
private File remotebase; private File remotebase;
private File remotedir; private File remotedir;
@ -91,7 +86,8 @@ public class SSHJava extends Java {
public SSHJava() { public SSHJava() {
super(); super();
setFork(true); setFork(true);
exec = new SSHExec(); exec = new SSHExecute();
exec.setProject(getProject());
scp = new Scp(); scp = new Scp();
userInfo = new SSHUserInfo(); userInfo = new SSHUserInfo();
} }
@ -107,7 +103,6 @@ public class SSHJava extends Java {
@Override @Override
public int executeJava() throws BuildException { public int executeJava() throws BuildException {
checkNotNull(jvm, "jvm must be set");
checkNotNull(remotebase, "remotebase must be set"); checkNotNull(remotebase, "remotebase must be set");
if (localDirectory == null) { if (localDirectory == null) {
@ -124,13 +119,13 @@ public class SSHJava extends Java {
if (osFamily == OsFamily.UNIX) { if (osFamily == OsFamily.UNIX) {
log("removing old contents: " + remotedir.getAbsolutePath(), Project.MSG_VERBOSE); log("removing old contents: " + remotedir.getAbsolutePath(), Project.MSG_VERBOSE);
exec.setCommand(exec("rm -rf " + remotedir.getAbsolutePath()).render(osFamily)); sshexec(exec("rm -rf " + remotedir.getAbsolutePath()).render(osFamily));
exec.execute();
} else { } else {
// TODO need recursive remove on windows // TODO need recursive remove on windows
} }
// must copy the files over first as we are changing the system properties based on this. // must copy the files over first as we are changing the system properties based on this.
String command = convertJavaToScriptNormalizingPaths(getCommandLine()); String command = createInitScript(osFamily, id, remotedir.getAbsolutePath(), env,
getCommandLine());
try { try {
BufferedWriter out = new BufferedWriter(new FileWriter(new File(localDirectory, "init." BufferedWriter out = new BufferedWriter(new FileWriter(new File(localDirectory, "init."
@ -162,27 +157,43 @@ public class SSHJava extends Java {
} }
if (osFamily == OsFamily.UNIX) { if (osFamily == OsFamily.UNIX) {
exec.setCommand(exec("chmod 755 " + remotedir.getAbsolutePath() + "{fs}init.{sh}").render( sshexec(exec("chmod 755 " + remotedir.getAbsolutePath() + "{fs}init.{sh}")
osFamily)); .render(osFamily));
exec.execute();
} }
Statement statement = new StatementList(exec("{cd} " + remotedir.getAbsolutePath()), Statement statement = new StatementList(exec("{cd} " + remotedir.getAbsolutePath()),
exec(remotedir.getAbsolutePath() + "{fs}init.{sh} init"), exec(remotedir exec(remotedir.getAbsolutePath() + "{fs}init.{sh} init"), exec(remotedir
.getAbsolutePath() .getAbsolutePath()
+ "{fs}init.{sh} run")); + "{fs}init.{sh} run"));
getProjectProperties().remove(id); try {
exec.setResultProperty(id); return sshexecRedirectStreams(statement);
exec.setFailonerror(false); } catch (IOException e) {
exec.setCommand(statement.render(osFamily)); throw new BuildException(e, getLocation());
exec.setError(errorFile); }
exec.setErrorproperty(errorProperty); }
exec.setOutput(outputFile);
exec.setOutputproperty(outputProperty); private int sshexec(String command) {
exec.setAppend(append); try {
return exec.execute(command);
} catch (JSchException e) {
throw new BuildException(e, getLocation());
} catch (IOException e) {
throw new BuildException(e, getLocation());
} catch (TimeoutException e) {
throw new BuildException(e, getLocation());
}
}
private int sshexecRedirectStreams(Statement statement) throws IOException {
exec.setStreamHandler(redirector.createHandler());
log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE); log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE);
exec.execute(); int rc;
return Integer.parseInt(getProject().getProperty(id)); try {
rc = sshexec(statement.render(osFamily));
} finally {
redirector.complete();
}
return rc;
} }
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) { private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
@ -190,19 +201,11 @@ public class SSHJava extends Java {
log("no content: " + destination, Project.MSG_DEBUG); log("no content: " + destination, Project.MSG_DEBUG);
return; return;
} }
exec.setCommand(exec("test -d " + destination).render(osFamily)); // TODO windows if (sshexec(exec("test -d " + destination).render(osFamily)) == 0) {// TODO windows
getProjectProperties().remove(id);
exec.setResultProperty(id);
exec.setFailonerror(false);
exec.execute();
if (getProject().getProperty(id).equals("0")) {
log("already created: " + destination, Project.MSG_VERBOSE); log("already created: " + destination, Project.MSG_VERBOSE);
return; return;
} }
getProjectProperties().remove(id); sshexec(exec("{md} " + destination).render(osFamily));
exec.setCommand(exec("{md} " + destination).render(osFamily));
exec.setFailonerror(true);
exec.execute();
scp.init(); scp.init();
String scpDestination = getScpDir(destination); String scpDestination = getScpDir(destination);
log("staging: " + scpDestination, Project.MSG_VERBOSE); log("staging: " + scpDestination, Project.MSG_VERBOSE);
@ -271,20 +274,21 @@ public class SSHJava extends Java {
return in; return in;
} }
String convertJavaToScriptNormalizingPaths(CommandlineJava commandLine) { String createInitScript(OsFamily osFamily, String id, String basedir, Environment env,
CommandlineJava commandLine) {
Map<String, String> envVariables = Maps.newHashMap(); Map<String, String> envVariables = Maps.newHashMap();
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_DEBUG);
String[] keyValue = environment[i].split("="); String[] keyValue = environment[i].split("=");
envVariables.put(keyValue[0], keyValue[1]); envVariables.put(keyValue[0], keyValue[1]);
} }
} }
StringBuilder commandBuilder = new StringBuilder(jvm); StringBuilder commandBuilder = new StringBuilder(commandLine.getVmCommand().getExecutable());
if (getCommandLine().getBootclasspath() != null) { if (commandLine.getBootclasspath() != null) {
commandBuilder.append(" -Xbootclasspath:bootclasspath"); commandBuilder.append(" -Xbootclasspath:bootclasspath");
resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getBootclasspath(), resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getBootclasspath(),
"bootclasspath", commandBuilder); "bootclasspath", commandBuilder);
@ -314,8 +318,8 @@ public class SSHJava extends Java {
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments())); Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
} }
InitBuilder testInitBuilder = new InitBuilder(id, remotedir.getAbsolutePath(), remotedir InitBuilder testInitBuilder = new InitBuilder(id, basedir, basedir, envVariables,
.getAbsolutePath(), envVariables, commandBuilder.toString()); commandBuilder.toString());
String script = testInitBuilder.build(osFamily); String script = testInitBuilder.build(osFamily);
return reprefix(script); return reprefix(script);
} }
@ -348,11 +352,6 @@ public class SSHJava extends Java {
throw new IllegalArgumentException("this only operates when fork is set"); throw new IllegalArgumentException("this only operates when fork is set");
} }
@Override
public void setJvm(String jvm) {
this.jvm = checkNotNull(jvm, "jvm");
}
/** /**
* Remote host, either DNS name or IP. * Remote host, either DNS name or IP.
* *
@ -364,15 +363,6 @@ public class SSHJava extends Java {
scp.setHost(host); scp.setHost(host);
} }
/**
* Get the host.
*
* @return the host
*/
public String getHost() {
return exec.getHost();
}
/** /**
* Username known to remote host. * Username known to remote host.
* *
@ -459,27 +449,6 @@ public class SSHJava extends Java {
scp.setPort(port); scp.setPort(port);
} }
/**
* Get the port attribute.
*
* @return the port
*/
public int getPort() {
return exec.getPort();
}
/**
* Initialize the task. This initializizs the known hosts and sets the default port.
*
* @throws BuildException
* on error
*/
public void init() throws BuildException {
super.init();
exec.init();
scp.init();
}
/** /**
* The connection can be dropped after a specified number of milliseconds. This is sometimes * 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 &quot;wait forever&quot;. * useful when a connection may be flaky. Default is 0, which means &quot;wait forever&quot;.
@ -491,43 +460,6 @@ public class SSHJava extends Java {
exec.setTimeout(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
public void setError(File error) {
this.errorFile = error;
}
@Override
public void setErrorProperty(String property) {
errorProperty = property;
}
@Override
public void setOutput(File out) {
outputFile = out;
}
@Override
public void setOutputproperty(String outputProp) {
outputProperty = outputProp;
}
@Override
public void setAppend(boolean append) {
this.append = append;
}
@Override @Override
public void setProject(Project project) { public void setProject(Project project) {
super.setProject(project); super.setProject(project);
@ -538,45 +470,40 @@ public class SSHJava extends Java {
@Override @Override
public void setOwningTarget(Target target) { public void setOwningTarget(Target target) {
super.setOwningTarget(target); super.setOwningTarget(target);
exec.setOwningTarget(target);
scp.setOwningTarget(target); scp.setOwningTarget(target);
} }
@Override @Override
public void setTaskName(String taskName) { public void setTaskName(String taskName) {
super.setTaskName(taskName); super.setTaskName(taskName);
exec.setTaskName(taskName);
scp.setTaskName(taskName); scp.setTaskName(taskName);
} }
@Override @Override
public void setDescription(String description) { public void setDescription(String description) {
super.setDescription(description); super.setDescription(description);
exec.setDescription(description);
scp.setDescription(description); scp.setDescription(description);
} }
@Override @Override
public void setLocation(Location location) { public void setLocation(Location location) {
super.setLocation(location); super.setLocation(location);
exec.setLocation(location);
scp.setLocation(location); scp.setLocation(location);
} }
@Override @Override
public void setTaskType(String type) { public void setTaskType(String type) {
super.setTaskType(type); super.setTaskType(type);
exec.setTaskType(type);
scp.setTaskType(type); scp.setTaskType(type);
} }
@Override @Override
public String toString() { public String toString() {
return "SSHJava [append=" + append + ", env=" + env + ", errorFile=" + errorFile return "SSHJava [append=" + append + ", env=" + env + ", errorFile=" + errorFile
+ ", errorProperty=" + errorProperty + ", jvm=" + jvm + ", localDirectory=" + ", errorProperty=" + errorProperty + ", localDirectory=" + localDirectory
+ localDirectory + ", osFamily=" + osFamily + ", outputFile=" + outputFile + ", osFamily=" + osFamily + ", outputFile=" + outputFile + ", outputProperty="
+ ", outputProperty=" + outputProperty + ", remoteDirectory=" + remotebase + outputProperty + ", remoteDirectory=" + remotebase + ", userInfo=" + userInfo
+ ", userInfo=" + userInfo + "]"; + "]";
} }
@Override @Override
@ -592,17 +519,4 @@ public class SSHJava extends Java {
} }
} }
@SuppressWarnings("unchecked")
Hashtable<String, String> getProjectProperties() {
PropertyHelper helper = (PropertyHelper) getProject().getReference(
MagicNames.REFID_PROPERTY_HELPER);
Field field;
try {
field = PropertyHelper.class.getDeclaredField("properties");
field.setAccessible(true);
return (Hashtable<String, String>) field.get(helper);
} catch (Exception e) {
throw new BuildException(e);
}
}
} }

View File

@ -47,28 +47,9 @@ public class SSHJavaTest {
.entrySet()); .entrySet());
// TODO, this test will break in windows // TODO, this test will break in windows
@Test(enabled = false) public void testShift() throws SecurityException, NoSuchMethodException {
public void testFull() throws SecurityException, NoSuchMethodException {
SSHJava task = makeSSHJava();
String expected = String
.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",
LAST_ENV.getKey(), LAST_ENV.getValue(), System.getProperty("java.home")
+ "/bin/java", LAST_ENV.getKey());
assertEquals(task.convertJavaToScriptNormalizingPaths(task.getCommandLine()), expected);
}
// TODO, this test will break in windows
@Test(enabled = false)
public void testFullShift() throws SecurityException, NoSuchMethodException {
SSHJava task = makeSSHJava(); SSHJava task = makeSSHJava();
task = directoryShift(task); task = directoryShift(task);
String expected = String
.format(
"export %s=\"%s\"%ncd /tmp/foo\n%s -Xms16m -Xmx32m -cp classpath -Dfooble=baz -Dfoo=bar -Dsettingsfile=/tmp/foo/maven/conf/settings.xml -DappHome=/tmp/foo/maven org.jclouds.tools.ant.TestClass %s hello world\n",
LAST_ENV.getKey(), LAST_ENV.getValue(), System.getProperty("java.home")
+ "/bin/java", LAST_ENV.getKey());
assertEquals(task.convertJavaToScriptNormalizingPaths(task.getCommandLine()), expected);
assertEquals(task.shiftMap, ImmutableMap.<String, String> of(System.getProperty("user.home") assertEquals(task.shiftMap, ImmutableMap.<String, String> of(System.getProperty("user.home")
+ "/apache-maven-2.2.1", "maven")); + "/apache-maven-2.2.1", "maven"));
} }
@ -160,20 +141,10 @@ public class SSHJavaTest {
} }
} }
public void testSSHJavaPropertyOverride() {
SSHJava task = new SSHJava();
Project p = new Project();
task.setProject(p);
p.setProperty("foo", "bar");
task.getProjectProperties().remove("foo");
assertEquals(p.getProperty("foo"), null);
}
private SSHJava makeSSHJava() { private SSHJava makeSSHJava() {
SSHJava task = new SSHJava(); SSHJava task = new SSHJava();
populateTask(task); populateTask(task);
task.setRemotebase(new File("/tmp/foo")); task.setRemotebase(new File("/tmp/foo"));
task.setVerbose(true);
task.setTrust(true); task.setTrust(true);
return task; return task;
} }