Reputation:
Once my program has been launched, it opens any number of ssh sessions (user defined) and runs specific commands on the servers indefinitely (while true loop) or until the user quits. For efficiency reasons I want to create each session only once, then be able to run the commands until the user quits.
How can I do this in python? I ran across a cool method in another post which used subprocess
to run a command and capture its STDOUT. How can I first initiate the session, then run looped commands?
Any links to process-like stuff in Python would also be appreciated. This is my first python application.
Upvotes: 5
Views: 3956
Reputation: 41
OPTION 1: You can re-use a ssh process by redirecting input using a PIPE.
Here is a basic example:
[(Z) </tmp> ]% touch input_file
[(Z) </tmp> ]% tailf input_file | ssh <remote_host>
Now try writing something into the file
[(Z) </tmp> ]% echo "date" >> /tmp/input_file
Here is a way to make use of this in Python using subprocess module.
import subprocess
SSH_CMD = "cat -| /usr/bin/ssh -o PasswordAuthentication=no -T -x %s "
HOSTNAME = "127.0.0.1"
s = subprocess.Popen(SSH_CMD%HOSTNAME , shell=True, close_fds=True,
stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
This starts a subprocess which can be re-used. Please note that close_fds=True
is required because of a known bug (http://bugs.python.org/issue2320).
>>> REMOTE_CMD = "date"
>>> s.stdin.write( REMOTE_CMD +
... "\necho 'remote command completed with exit code = '$?\n")
>>> s.stdout.readline()
'Thu Feb 16 20:01:36 PST 2012\n'
>>> s.stdout.readline()
'remote command completed with exit code = 0\n'
echo 'remote command completed with exit code = '$?\n
line is used to know that the remote command finished and it is done writing to s.stdout. This is also useful to know the exit code of the remote command.
To use the same subprocess for executing another remote command:
>>> REMOTE_CMD = "uptime"
>>> s.stdin.write( REMOTE_CMD +
... "\necho 'remote command completed with exit code = '$?\n")
>>> s.stdout.readline()
' 20:02:17 up 28 days, 9:15, 48 users, load average: 0.01, 0.02, 0.05\n'
>>> s.stdout.readline()
'remote command completed with exit code = 0\n'
Coming back to your question, once you create a ssh subprocess, you can keep sending the remote commands. Once the user is quits, you can kill the subprocess.
>>> s.kill()
OPTION 2: I have never used this, but ssh has a ControlMaster option for re-using ssh. Check man page for ssh_config(5)
Upvotes: 4
Reputation: 259
Try using pexpect module. It allows opening and maintaining ssh sessions, which you can reuse to send in multiple commands. You can send in any commands and expect particular outputs based on which you can perform other logical operations.
Upvotes: 0
Reputation: 315
Ignoring Python for the moment, you can multiplex ssh
sessions by adding this
ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r
ControlPersist 1h
to your ~/.ssh/config
file. After connecting to a machine once, the ssh session to this machine will stay open, and subsequent commands will execute on this machine near-instantaneously thereafter. You could then use Python subprocess to call ssh and execute commands on that machine as-needed, and the session will be reused without having to do anything special.
You could also call ssh
with the -F
flag pointing to an alternate config file, if you'd rather not make the session multiplexing the default behavior (or you're deploying for other users who might not have it as their default).
Upvotes: 6