Home » Odeon Blogs » Stefan Talpalaru, CTO »

automating remote commands over SSH with paramiko

automating remote commands over SSH with paramiko

I don't know how high ranking python is for automating system administration tasks but when I had to script remote ssh commands, I thought I'd give python a try. The main SSH library is paramiko and, while lacking in the documentation department, it's rather rich in features.

Besides the usual root login, I had a more difficult use case: using a regular user with full sudo rights instead of the superuser. These are the functions I came up with:

  1. import paramiko
  2. import getpass
  3. def ssh_connection(user, host, port=22, password=None, key_filename=None):
  4. """
  5. with password='' you will be prompted for a password when the script runs
  6. """
  7. ssh = paramiko.SSHClient()
  8. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  9. if password == '':
  10. # ask for one on stdin
  11. password = getpass.getpass('Password for %s@%s: ' % (user, host))
  12. ssh.connect(host, port=port, username=user, password=password, key_filename=key_filename)
  13. # custom attributes
  14. ssh.user = user
  15. if user == 'root':
  16. ssh.homedir = '/root'
  17. else:
  18. ssh.homedir = '/home/%s' % user
  19. ssh.password = password
  20. ssh.use_sudo = False
  21. return ssh
  22. def run_remote(ssh, cmd, check_exit_status=True, verbose=True):
  23. chan = ssh.get_transport().open_session()
  24. stdin = chan.makefile('wb')
  25. stdout = chan.makefile('rb')
  26. stderr = chan.makefile_stderr('rb')
  27. processed_cmd = cmd
  28. if ssh.use_sudo:
  29. processed_cmd = 'sudo -S bash -c "%s"' % cmd.replace('"', '\\"')
  30. chan.exec_command(processed_cmd)
  31. if stdout.channel.closed is False: # If stdout is still open then sudo is asking us for a password
  32. stdin.write('%s\n' % ssh.password)
  33. stdin.flush()
  34. result = {
  35. 'stdout': [],
  36. 'stderr': [],
  37. }
  38. exit_status = chan.recv_exit_status()
  39. result['exit_status'] = exit_status
  40. def print_output():
  41. for line in stdout:
  42. result['stdout'].append(line)
  43. print line,
  44. for line in stderr:
  45. result['stderr'].append(line)
  46. print line,
  47. if check_exit_status and exit_status != 0:
  48. print_output()
  49. print 'non-zero exit status (%d) when running "%s"' % (exit_status, cmd)
  50. exit(exit_status)
  51. if verbose:
  52. print processed_cmd
  53. print_output()
  54. return result
Notice the cool multiline command string that works even with sudo. We need to pass multiple commands because paramiko opens a new session for each exec_command() invocation so the current directory is reset on subsequent calls. Let's see some examples:
  1. # set up a ssh connection for root and ask for the password interactively
  2. myconn = ssh_connection('root', 'example.com', password='')
  3. # run some commands with the default settings
  4. run_remote(myconn,
  5. """
  6. pwd
  7. cd /var/log
  8. pwd
  9. ls -la
  10. """)
  11. # set up a connection for a regular user with full sudo rights and use it for running commands with root privileges
  12. sudoconn = ssh_connection('jim', 'example.com', password='imanewbieandileavepasswordsintextfiles')
  13. sudoconn.use_sudo = True
  14. run_remote(sudoconn,
  15. """
  16. whoami
  17. pwd
  18. cd /var/log
  19. pwd
  20. ls -la
  21. """)
You can suppress the exit code checking and the verbosity if you want and handle that info from the returned dictionary any way it suits you.

Bottom line, it might not be easy to use paramiko's API directly but it's trivial to use my functions so go ahead and script those repetitive administration tasks. As always when doing stuff as root, try not to hose the server ;-)


Category: Python

Discussion

  1. Try Fabric. It's easier to use the API. Perfect for deployments and sysadmin tasks


  2. Gary on Dec 13, 2011 - 18:41 said:

    Great blog and thanks for the example definitions however when trying to test them I am having issues. Is there a chance you might be able to actually make a couple example files and post them?

    Thanks!


  3. Gary on Dec 14, 2011 - 19:06 said:

    Nevermind my previous comment as I have tried to build the include file again and the defs are now successfully working. Thanks alot for the example!




Leave a Comment :

(required)


(required)




(required)




(required)






Leave a Comment


Page generated in: 0.24s