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.

Reply via email to