Wednesday, December 8, 2010

Running remote command over ssh with Groovy

This post is for those who are searching for how to run a remote command over ssh through a groovy script.  Hopefully it will save someone a lot of searching....spoiler alert:  There does not seem to be a clean way to do this.

It is trivial to run a command on a remote system over ssh, especially if you have keys set up between the machines that are communicating.  Just
ssh user@remote_server command_you_would_like_to_run'.

Things get surprisingly complicated when you want to script this kind of interaction.  I believe that this is because most ssh implementations use tty and it is made difficult by design to use in a scripted environment (and rightly so, since it is a security risk).

I simply wanted to connect to a remote server with groovy and list the files in a known directory.  I was hoping that I could do this with groovy's .execute().text since I did not need to send passwords or anything else because I have keys set up between the machines.  No dice.  I tried the array version of .execute too and still no joy.  What I ended up having to do is to create a simple bash script:

 #!/bin/bash
 ssh user@remote_server 'ls /directory_I_am_interested_in'


which I called ls_script so my groovy line became:


 def listOfFiles = "ls_script".execute().text


I did not like calling outside of the original script but it is quick and it works.

If it makes sense for the overall job at hand, there is a wonderful python library called pexpect .  Somehow this great little library very cleanly bypasses the tty issues I mentioned earlier.

Here is a simple use case of pexpect:


 spawnString = 'ssh ' + thisLogin + '@' + thisIP + ' -p ' + thisPort
 foo = pexpect.spawn(spawnString)
 ssh_newkey = 'Are you sure you want to continue connecting'
 i = foo.expect([ssh_newkey, 'password'])
        if i == 0:
            foo.sendline('yes')
            i = foo.expect([ssh_newkey, 'password'])
        if i == 1:
            foo.sendline(thisPassword)
 foo.sendline(' ')
 data = foo.readline()


Checkout the sourceforge page and http://www.noah.org/wiki/pexpect which I believe is the original creator's site with some nice documentation.

No comments:

Post a Comment