Return-Path:
since Ant 1.8.0 A Task which establishes an SSH connection with a remote machine
+running SSH daemon, optionally establishes any number of local or
+remote tunnels over that connection, then executes any nested tasks
+before taking down the connection.
+ Note: This task depends on external libraries not included
+in the Ant
+distribution. See Library
+Dependencies for more information. This task has been tested with
+jsch-0.1.33 and above and won't work with versions of jsch earlier
+than 0.1.28. See also the sshexec
+and scp tasks Optionally, any number of localtunnel elements can be used to
+define local port forwarding over the SSH connection. If the
+localtunnels parameter was also specified, both sets of tunnels will
+be established. Optionally, any number of remotetunnel elements can be used to
+define remote port forwarding over the SSH connection. If the
+remotetunnels parameter was also specified, both sets of tunnels will
+be established. The sequential element is a required parameter. It is a container
+for nested Tasks which are to be executed once the SSH connection is
+established and all local and/or remote tunnels established. Connect to a remote machine using password authentication,
+forward the local cvs port to the remote host, and execute a cvs
+command locally, which can use the tunnel. Do the same thing using nested localtunnel element. Connect to a remote machine using key authentication, forward
+port 1080 to port 80 of an intranet server which is not directly
+accessible, then run a get task using that tunnel. Security Note: Hard coding passwords or
+passphrases and/or usernames in sshsession task can be a serious
+security hole. Consider using variable substitution and include the
+password on the command line. For example:SSHSESSION
+Description
+
+Parameters
+
+
+
+
+
+ Attribute
+ Description
+ Required
+
+
+ host
+ The hostname or IP address of the remote host to which you wish to connect.
+ Yes
+
+
+ username
+ The username on the remote host to which you are connecting.
+ Yes
+
+
+ port
+ The port to connect to on the remote host.
+ No, defaults to 22.
+
+
+
+ localtunnels
+ A comma-delimited list of
+ colon-delimited
+ lport:rhost:rport
triplets defining
+ local port forwarding.
If
+ nested localtunnel elements are also
+ provided, both sets of tunnels will be established.No
+
+
+ remotetunnels
+ A comma-delimited list of
+ colon-delimited
+ rport:lhost:lport
triplets defining
+ remote port forwarding.
If
+ nested remotetunnel elements are
+ also provided, both sets of tunnels will be established.No
+
+
+ trust
+
+ This trusts all unknown hosts if set to yes/true.
+
+ Note If you set this to false (the default), the
+ host you connect to must be listed in your knownhosts file, this
+ also implies that the file exists.No, defaults to No.
+
+
+ knownhosts
+ This sets the known hosts file to use to validate
+ the identity of the remote host. This must be a SSH2 format file.
+ SSH1 format is not supported.
+ No, defaults to
+ ${user.home}/.ssh/known_hosts.
+
+
+ failonerror
+ Whether to halt the build if the command does not complete successfully.
+
+ No; defaults to true.
+
+
+ password
+ The password.
+ Not if you are using key based
+ authentication or the password has been given in the file or
+ todir attribute.
+
+
+ keyfile
+ Location of the file holding the private key.
+ Yes, if you are using key based
+ authentication.
+
+
+ passphrase
+ Passphrase for your private key.
+ No, defaults to an empty string.
+
+
+timeout
+ Give up if the connection cannot be established
+ within the specified time (given in milliseconds). Defaults to 0
+ which means "wait forever".
+ No
+ Parameters specified as nested elements
+
+localtunnel
+
+
+
+
+
+ Attribute
+ Description
+ Required
+
+
+ lport
+ The number of the local port to be forwarded.
+ Yes
+
+
+ rhost
+ The hostname or IP address of the remote host to
+ which the local port should be forwarded.
+ Yes
+
+
+rport
+ The number of the port on the remote host to
+ which the local port should be forwarded.
+ Yes
+ remotetunnel
+
+
+
+
+
+ Attribute
+ Description
+ Required
+
+
+ rport
+ The number of the remote port to be forwarded.
+ Yes
+
+
+ lhost
+ The hostname or IP address of the local host to
+ which the remote port should be forwarded.
+ Yes
+
+
+lport
+ The number of the port on the local host to which
+ the remote port should be forwarded.
+ Yes
+ sequential
+Examples
+
+ <sshsession host="somehost"
+ username="dude"
+ password="yo"
+ localtunnels="2401:localhost:2401"
+ >
+ <sequential>
+ <cvs command="update ${cvs.parms} ${module}"
+ cvsRoot="${cvs.root}"
+ dest="${local.root}"
+ failonerror="true"
+ />
+ </sequential>
+ </sshsession>
+
+
+
+ <sshsession host="somehost"
+ username="dude"
+ password="yo"
+ >
+ <localtunnel lport="2401" rhost="localhost" rport="2401"/>
+ <sequential>
+ <cvs command="update ${cvs.parms} ${module}"
+ cvsRoot="${cvs.root}"
+ dest="${local.root}"
+ failonerror="true"
+ />
+ </sequential>
+ </sshsession>
+
+
+
+ <sshsession host="somehost"
+ username="dude"
+ keyfile="${user.home}/.ssh/id_dsa"
+ passphrase="yo its a secret"/>
+ <LocalTunnel lport="1080" rhost="intranet.mycomp.com" rport="80"/>
+ <sequential>
+ <get src="http://localhost:1080/somefile" dest="temp/somefile"/>
+ </sequential>
+ </sshsession>
+
+
+
+
+
+ <sshsession host="somehost"
+ username="${username}"
+ password="${password}"
+ localtunnels="2401:localhost:2401">
+ <sequential>
+ <sometask/>
+ </sequential>
+ </sshsession>
+
+
+Invoking ant with the following command line:
+
+ ant -Dusername=me -Dpassword=mypassword target1 target2
+
+
+Is slightly better, but the username/password is exposed to all users
+on an Unix system (via the ps command). The best approach is to use
+the
+<input>
task and/or retrieve the password from a (secured)
+.properties file.
+
+ * @param nestedTask Nested task to execute Sequential + *
+ */ + public void addTask(Task nestedTask) { + nestedTasks.addElement(nestedTask); + } + + /** + * 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; + } + + /** + * Changes the comma-delimited list of local tunnels to establish + * on the connection. + * + * @param tunnels a comma-delimited list of lport:rhost:rport + * tunnel specifications + */ + public void setLocaltunnels(String tunnels) { + String[] specs = tunnels.split(", "); + for (int i = 0; i < specs.length; i++) { + if (specs[i].length() > 0) { + String[] spec = specs[i].split(":", 3); + int lport = Integer.parseInt(spec[0]); + String rhost = spec[1]; + int rport = Integer.parseInt(spec[2]); + LocalTunnel tunnel = createLocalTunnel(); + tunnel.setLPort(lport); + tunnel.setRHost(rhost); + tunnel.setRPort(rport); + } + } + } + + /** + * Changes the comma-delimited list of remote tunnels to establish + * on the connection. + * + * @param tunnels a comma-delimited list of rport:lhost:lport + * tunnel specifications + */ + public void setRemotetunnels(String tunnels) { + String[] specs = tunnels.split(", "); + for (int i = 0; i < specs.length; i++) { + if (specs[i].length() > 0) { + String[] spec = specs[i].split(":", 3); + int rport = Integer.parseInt(spec[0]); + String lhost = spec[1]; + int lport = Integer.parseInt(spec[2]); + RemoteTunnel tunnel = createRemoteTunnel(); + tunnel.setRPort(rport); + tunnel.setLHost(lhost); + tunnel.setLPort(lport); + } + } + } + + + /** + * Establish the ssh session and execute all nestedTasks + * + * @exception BuildException if one of the nested tasks fails, or + * 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 (nestedSequential == null) { + throw new BuildException("Missing sequential element."); + } + + + Session session = null; + try { + // establish the session + session = openSession(); + session.setTimeout((int) maxwait); + + for (Iterator i = localTunnels.iterator(); i.hasNext();) { + LocalTunnel tunnel = (LocalTunnel) i.next(); + session.setPortForwardingL(tunnel.getLPort(), + tunnel.getRHost(), + tunnel.getRPort()); + } + + for (Iterator i = remoteTunnels.iterator(); i.hasNext();) { + RemoteTunnel tunnel = (RemoteTunnel) i.next(); + session.setPortForwardingR(tunnel.getRPort(), + tunnel.getLHost(), + tunnel.getLPort()); + } + + for (Iterator i = nestedSequential.getNested().iterator(); + i.hasNext();) { + Task nestedTask = (Task) i.next(); + nestedTask.perform(); + } + // completed successfully + + } 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 (BuildException e) { + // avoid wrapping it into yet another BuildException further down + throw e; + } catch (Exception e) { + if (getFailonerror()) { + throw new BuildException(e); + } else { + log("Caught exception: " + e.getMessage(), Project.MSG_ERR); + } + } finally { + if (session != null && session.isConnected()) { + session.disconnect(); + } + } + } + + public LocalTunnel createLocalTunnel() { + LocalTunnel tunnel = new LocalTunnel(); + localTunnels.add(tunnel); + return tunnel; + } + + public RemoteTunnel createRemoteTunnel() { + RemoteTunnel tunnel = new RemoteTunnel(); + remoteTunnels.add(tunnel); + return tunnel; + } + + public class LocalTunnel { + public LocalTunnel() {} + + int lport = 0; + String rhost = null; + int rport = 0; + public void setLPort(int lport) { + Integer portKey = new Integer(lport); + if (localPortsUsed.contains(portKey)) + throw new BuildException("Multiple local tunnels defined to" + + " use same local port " + lport); + localPortsUsed.add(portKey); + this.lport = lport; + } + public void setRHost(String rhost) { this.rhost = rhost; } + public void setRPort(int rport) { this.rport = rport; } + public int getLPort() { + if (lport == 0) throw new BuildException("lport is required for" + + " LocalTunnel."); + return lport; + } + public String getRHost() { + if (rhost == null) throw new BuildException("rhost is required" + + " for LocalTunnel."); + return rhost; + } + public int getRPort() { + if (rport == 0) throw new BuildException("rport is required for" + + " LocalTunnel."); + return rport; + } + } + + public class RemoteTunnel { + public RemoteTunnel() {} + + int lport = 0; + String lhost = null; + int rport = 0; + public void setLPort(int lport) { this.lport = lport; } + public void setLHost(String lhost) { this.lhost = lhost; } + public void setRPort(int rport) { + Integer portKey = new Integer(rport); + if (remotePortsUsed.contains(portKey)) + throw new BuildException("Multiple remote tunnels defined to" + + " use same remote port " + rport); + remotePortsUsed.add(portKey); + this.rport = rport; + } + public int getLPort() { + if (lport == 0) throw new BuildException("lport is required for" + + " RemoteTunnel."); + return lport; + } + public String getLHost() { + if (lhost == null) throw new BuildException("lhost is required for" + + " RemoteTunnel."); + return lhost; + } + public int getRPort() { + if (rport == 0) throw new BuildException("rport is required for" + + " RemoteTunnel."); + return rport; + } + } + + /** + * This is the sequential nested element of the macrodef. + * + * @return a sequential element to be configured. + */ + public NestedSequential createSequential() { + if (this.nestedSequential != null) { + throw new BuildException("Only one sequential allowed"); + } + this.nestedSequential = new NestedSequential(); + return this.nestedSequential; + } + + /** + * The class corresponding to the sequential nested element. + * This is a simple task container. + */ + public static class NestedSequential implements TaskContainer { + private List nested = new ArrayList(); + + /** + * Add a task or type to the container. + * + * @param task an unknown element. + */ + public void addTask(Task task) { + nested.add(task); + } + + /** + * @return the list of unknown elements + */ + public List getNested() { + return nested; + } + } + +} Propchange: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java ------------------------------------------------------------------------------ svn:eol-style = native