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.