32

I'm going to write first code for handling ssh commands on python and I did search over the stackoverflow and can see that there are several python libraries that can be used for handling commands passed through ssh, like paramiko, pexpect and perhaps some others.

Particularly, I will need to read content of the files from the remote server, copy files through ssh/scp, get output from remote server after starting the script on remote server.

Perhaps some experts could advice what library is better and specify advantages or disadvantages?

yart
  • 7,515
  • 12
  • 37
  • 37

4 Answers4

32

Since you're not doing anything special at the protocol level, you presumably don't need the protocol to be entirely implemented in python, and you could simply run ssh/scp commands using the subprocess module.

import subprocess
subprocess.check_call(['ssh', 'server', 'command'])
subprocess.check_call(['scp', 'server:file', 'file'])
Tobu
  • 24,771
  • 4
  • 91
  • 98
  • 11
    No idea why you got downvoted, but I I've looked around and this is still the best solution for people who ned their code working on machines where they don't want to install a set of libraries. – saccharine Jul 29 '13 at 22:11
  • 1
    Yeah. It will also make use of host aliases, ProxyCommands and other ~/.ssh/config settings. – Tobu Feb 08 '14 at 08:26
  • 3
    Reasons for downvoting: Relies on external binaries. Not cross platform. Not programmatic, as in relies on externally provided configuration and keys. Running sequential sub processes has lots of overhead and does not scale well for multiple remote hosts. There's more but those are the important ones. – danny Aug 25 '16 at 13:50
  • 1
    @danny, it matches my use case perfectly, and I am sure it does for many other people. – wobbily_col Aug 30 '16 at 09:06
  • 3
    @wobbily_col I am sure it does, however, the OP is specifically asking for python libraries. The OpenSSH binaries are not it. – danny Aug 31 '16 at 14:24
  • 1
    I searched for "python libraries" also but I realize this solution is far simpler without needing them, so I think its pretty relevant. Its simpler then formulating a question that covers this answer as well as liraries. – wobbily_col Aug 31 '16 at 20:03
  • The problem of this approach is that it can run into ambiguity. For example, if you get back "could not connect to remote host", you cannot distinguish if the message is coming from remote program or from ssh itself. So it is impossible to write robust code without additional assumptions. – jurez Mar 15 '19 at 18:24
  • This is the easiest option in some cases but has drawback of establishing a connection for every command. If you want to run many commands but not in a batch mode then it will slow things down significantly. If that's not a concern this is a good option still. – yǝsʞǝla Nov 25 '22 at 01:20
  • @saccharine exactly my case. I want to keep the code as clean as possible from locally installed libraries. – runlevel0 Apr 20 '23 at 14:55
26

Libraries, Wrappers:

  1. http://www.lag.net/paramiko/

    #!/usr/bin/env python
    import paramiko
    from contextlib import contextmanager
    host = '192.168.10.142'
    username = 'slacker'
    password = 'password'
    def create_ssh(host=host, username=username, password=password):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
        try:
           print "creating connection"
           ssh.connect(host, username=username, password=password)
           print "connected"
           yield ssh
        finally:
           print "closing connection"
           ssh.close()
           print "closed"
    

1) utilizes the 2) and provides some higher level functions. If the latter suit your requirements, I'd suggest trying out 1)


Update: 1) is gone now (2017-09-12)

  1. http://media.commandline.org.uk/code/ssh.txt (example usage: https://zeth.net/archive/2008/05/29/sftp-python-really-simple-ssh/)

    s = ssh.Connection('example.com', 'warrior', password = 'lennalenna')
    s.put('/home/warrior/hello.txt', '/home/zombie/textfiles/report.txt')
    s.get('/var/log/strange.log', '/home/warrior/serverlog.txt')
    s.execute('ls -l')
    s.close()
    

Note: The code examples above are provided just for getting an impression; the code is not tested.

miku
  • 181,842
  • 47
  • 306
  • 310
5

The one feature that none of the above-discussed libraries provide is a concurrent connection to multiple servers.In today's age where system admins need to run commands on hundreds of servers,libraries which can handle parallel command execution are very important. The two libraries that I know of are :

  1. Trigger

  2. Parallel-SSH

Trigger is much more than a SSH wrapper and more of a networking library,it utilizes the Twisted core API to enable concurrent I/O operations.

Parallel-SSH is a library which is thin wrapper over Paramiko but uses Gevent under the hood to enable concurrent I/O operations

Amistad
  • 7,100
  • 13
  • 48
  • 75
  • Seconding the concurrency point. Furthermore, Parallel-SSH in particular supports SFTP natively as well as SSH features like proxying and agent forwarding, all using asynchronous network I/O via gevent. – danny Aug 04 '16 at 10:58
3

Try taking a look at Twisted Conch. It handles everything you want. If you were just looking for SCP-style file transfer, you could always use the python module secsh-filexfer.

Douglas Mayle
  • 21,063
  • 9
  • 42
  • 57