Perform commands over ssh with Python

2019-01-01 08:15发布

问题:

I\'m writing a script to automate some command line commands in Python. At the moment I\'m doing calls thus:

cmd = \"some unix command\"
retcode = subprocess.call(cmd,shell=True)

However I need to run some commands on a remote machine. Manually, I would log in using ssh and then run the commands. How would I automate this in Python? I need to log in with a (known) password to the remote machine, so I can\'t just use cmd = ssh user@remotehost, I\'m wondering if there\'s a module I should be using?

回答1:

I will refer you to paramiko

see this question

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd_to_execute)


回答2:

Or you can just use commands.getstatusoutput:

   commands.getstatusoutput(\"ssh machine 1 \'your script\'\")

I used it extensively and it works great.

In Python 2.6+, use subprocess.check_output.



回答3:

Have you had a look at Fabric? It allows you to do all sorts of remote stuff over SSH using python.



回答4:

I found paramiko to be a bit too low-level, and Fabric not especially well-suited to being used as a library, so I put together my own library called spur that uses paramiko to implement a slightly nicer interface:

import spur

shell = spur.SshShell(hostname=\"localhost\", username=\"bob\", password=\"password1\")
result = shell.run([\"echo\", \"-n\", \"hello\"])
print result.output # prints hello

If you need to run inside a shell:

shell.run([\"sh\", \"-c\", \"echo -n hello\"])


回答5:

All have already stated (recommended) using paramiko and I am just sharing a python code (API one may say) that will allow you to execute multiple commands in one go.

to execute commands on different node use : Commands().run_cmd(host_ip, list_of_commands)

You will see one TODO, which I have kept to stop the execution if any of the commands fails to execute, I don\'t know how to do it. please share your knowledge

#!/usr/bin/python

import os
import sys
import select
import paramiko
import time


class Commands:
    def __init__(self, retry_time=0):
        self.retry_time = retry_time
        pass

    def run_cmd(self, host_ip, cmd_list):
        i = 0
        while True:
        # print(\"Trying to connect to %s (%i/%i)\" % (self.host, i, self.retry_time))
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(host_ip)
            break
        except paramiko.AuthenticationException:
            print(\"Authentication failed when connecting to %s\" % host_ip)
            sys.exit(1)
        except:
            print(\"Could not SSH to %s, waiting for it to start\" % host_ip)
            i += 1
            time.sleep(2)

        # If we could not connect within time limit
        if i >= self.retry_time:
            print(\"Could not connect to %s. Giving up\" % host_ip)
            sys.exit(1)
        # After connection is successful
        # Send the command
        for command in cmd_list:
            # print command
            print \"> \" + command
            # execute commands
            stdin, stdout, stderr = ssh.exec_command(command)
            # TODO() : if an error is thrown, stop further rules and revert back changes
            # Wait for the command to terminate
            while not stdout.channel.exit_status_ready():
                # Only print data if there is data to read in the channel
                if stdout.channel.recv_ready():
                    rl, wl, xl = select.select([ stdout.channel ], [ ], [ ], 0.0)
                    if len(rl) > 0:
                        tmp = stdout.channel.recv(1024)
                        output = tmp.decode()
                        print output

        # Close SSH connection
        ssh.close()
        return

def main(args=None):
    if args is None:
        print \"arguments expected\"
    else:
        # args = {\'<ip_address>\', <list_of_commands>}
        mytest = Commands()
        mytest.run_cmd(host_ip=args[0], cmd_list=args[1])
    return


if __name__ == \"__main__\":
    main(sys.argv[1:])

Thank you!



回答6:

I have used paramiko a bunch (nice) and pxssh (also nice). I would recommend either. They work a little differently but have a relatively large overlap in usage.



回答7:

Have a look at spurplus, a wrapper we developed around spur that provides type annotations and some minor gimmicks (reconnecting SFTP, md5 etc.): https://pypi.org/project/spurplus/



标签: python ssh