Steve Loughran said:
>>> What is your new task trying to do?
>>
>> It is sshsession, a container task which establishes an SSH connection,
>> and optionally any number of local or remote tunnels over that
connection,
>> then executes any nested tasks before taking down the connection.
>>
>> My purpose in writing it is that we use cvs, and secure all access by
only
>> allowing cvs connections from localhost, which are tunneled over SSH
>> connections.
>> Establishing those connections is the only manual step in an otherwise
>> automated
>> build process. While I could use exec to issue the putty command (this
is
>> done
>> on windoze) conditionally if a server is not already accessible at
>> localhost
>> port 2401, it gets more complicated with a passphrase on the keypair
being
>> used.
>> Furthermore, there was no way to ensure that an existing connection is
the
>> connection we should be using, and no way to bring the connection down
>> once we
>> are done with it.
>>
>> So I wrote SSHSession, extending SSHBase, and implementing
TaskContainer.
>> The TaskContainer implementation is lifted directly from Sequential,
and
>> the
>> remainder is adapted from SSHCommand, though all the command execution
>> related
>> properties and logic were removed. I added support for defining the
>> tunnels via
>> properties and/or nested elements. I only needed local port
forwarding,
>> but added
>> remote port forwarding for completeness. Using SSHSession with a local
>> tunnel
>> (2401:localhost:2401) and nested CVS commands does exactly what we
need.
>>
>> Example1: using nested <LocalTunnel> element and a cvs task
>> <sshsession host="cvshost.mydomain.com"
>> keyfile="${ssh.key.file}"
>> passphrase="${ssh.key.passphrase}"
>> username="${ssh.username}"
>> knownhosts="${ssh.knownhosts.file}">
>> <LocalTunnel lport="2401" rhost="localhost" rport="2401"/>
>> <cvs command="update ${cvs.parms} ${module}"
>> cvsRoot="${cvs.root}"
>> dest="${local.root}"
>> failonerror="true"/>
>> </sshsession>
>>
>> Example2: using localtunnels parameter (comma-delimited list of
>> colon-delimited lport:rhost:rport triplets)
>> <sshsession host="cvshost.mydomain.com"
>> localtunnels="2401:localhost:2401"
>> keyfile="${ssh.key.file}"
>> passphrase="${ssh.key.passphrase}"
>> username="${ssh.username}"
>> knownhosts="${ssh.knownhosts.file}">
>> <cvs command="update ${cvs.parms} ${module}"
>> cvsRoot="${cvs.root}"
>> dest="${local.root}"
>> failonerror="true"/>
>> </sshsession>
>>
>>
>
>this looks very nice indeed.
>
>1. <LocalTunnel> should be lower case only, to be consistent with
>everything else
>2. I'd put the nested commands into a <sequence>, the way we did in
><macrodef>. This makes it clear it is sequential, and it leaves room to
>add new things alongside <localtunnel>.
>
Thanks! I did resolve my issues with pulling together a patch, and
submitted it before you offered these latest suggestions. I'll revise the
doc to use lower case.
I'd like to discuss further your suggestion of incorporating <sequence>
(<sequential>, according to 1.7.0 doc??) into sshsession to hold the
nested tasks. Please explain further why this is prefereable. Multiple
tasks are supported now, and while by default, they execute in order,
someone could use a <parallel> task to get another behavior, if they
wish. Since the expected behavior of ant is to process tasks
sequentially unless a <parallel> task is used, why is sequential
processing within <sshsession> unclear? Also, I don't understand
how introduction of <sequential> makes it any easier to add other
things alongside <localtunnel> and <remotetunnel>?
The one thing I can see which might be confusing is that localtunnel
and remotetunnel can be interspersed with tasks, e.g.
<sshsession host=......>
<localtunnel lport="81" .../>
<sometask1/>
<localtunnel lport="82" .../>
<sometask2/>
<remotetunnel rport="1080" .../>
<sometask3/>
</sshsession>
In this example, two local tunnels and one remote tunnel would be
established before any tasks are run, and then the three tasks would
be run in sequential order.
A possible enhancement, however, would be to add support for a
nested <command> element within sshsession, providing a command
(and associated timeout and output parameters) to be executed on
the remote server using the established SSH session. In this
scenario, it could make sense that the order of the <command>
elements relative to nested tasks is preserved. In that case, an
internal Command class would be added, but the createCommand
method would add each instance to the same Vector which is storing
Tasks (via addTask). In SSHSession's execute method, I would have
to use "instanceof Command" when iterating over the Vector, and
use the logic from SSHExec to run Commands remotely, interspersed
with local Tasks, and executed in the order presented by the Vector.
<digression>
It might make sense to have Command extend Task (are there issues
with that if it isn't a Task Ant knows about?), even though it is
constructed via SSHSession, so that I don't have to treat any Vector
items differently, but the execute method of Command would need to
use the com.jcraft.jsch.Session created on the stack by SSHSession
execute method. That would require saving the Session as a member
variable of the SSHSession intance, instead of on the stack, thereby
making SSHSession non-threadsafe. That seems unlikely to be an
issue, except that <parallel> could be employed such that multiple
tasks running on separate threads call the same target, containing
the single SSHSession Task instance. I didn't see it in the guidelines
from the tutorial, but I assume that thread safety is a requirement in
Ant, due to the <parallel> Task. For this reason, I settled on the
approach where instanceof must be used, in order to implement
running the remote command within the nestedTask iterator loop in
SSHSession's execute method, and use the Command instances
as simple beans.
</digression>
So, if adding <command> elements interspersed with the nested
tasks makes sense as a possible future enhancement, then it seems
we should not require <sequential>, as that will not know how to
process <command>s.