2010-08-27 8 views
81

Я пишу скрипт для автоматизации некоторых команд командной строки в Python. В настоящий момент я звоню так:Выполнять команды по ssh с Python

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

Однако мне нужно выполнить некоторые команды на удаленной машине. Вручную, я должен войти в систему, используя ssh, а затем запустите команды. Как я могу автоматизировать это в Python? Мне нужно войти с помощью (известного) пароля на удаленный компьютер, поэтому я не могу просто использовать cmd = ssh [email protected], мне интересно, есть ли модуль, который я должен использовать?

+6

Проделал поиск, но этот вопрос справедлив по этой странице, и я не дошел так далеко. – fredley

ответ

120

Я отсылаю вас к paramiko

см 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

Предполагается, что парамико такой же безопасный, как (открытый) ssh. Это? – user239558

+0

Что делать, если ssh-ключи обмениваются? – Ardit

+1

@ R-Dit, для ключей ssh, попробуйте избавиться от параметра пароля и выполнить следующую команду перед подключением: 'ssh.load_system_host_keys()'. – alfonso

22

Вы имели в виду Fabric? Это позволяет вам делать всевозможные удаленные вещи поверх SSH с помощью python.

31

Или вы можете просто использовать commands.getstatusoutput:

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

Я широко использовали его, и он прекрасно работает.

В Python 2.6+ используйте subprocess.check_output.

+3

+1 для простого простого встроенного метода. В моей текущей настройке я не хочу добавлять библиотеки Python, поэтому ваше предложение ценно, очень просто. –

+2

просто убедитесь, что ваш удаленный хост настроен для бездействия ssh, если нет, вам нужно делать другие вещи для управления аутентификацией. – powerrox

+0

subprocess.check_output - отличное решение! –

3

Я использовал paramiko сгусток (хороший) и pxssh (также приятно). Я бы тоже порекомендовал. Они работают немного по-другому, но имеют относительно большое совпадение в использовании.

+2

Ссылка на pxssh - приятное путешествие назад во времени. –

11

Я нашел парамико слишком низкоуровневым, а Fabric не особенно хорошо подходит для использования в качестве библиотеки, поэтому я собрал свою собственную библиотеку под названием spur, которая использует paramiko для реализации немного более приятного интерфейса:

import spur 

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

Если вам нужно запустить внутри оболочки:

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

Я решил попробовать «spur». Вы генерируете дополнительные команды оболочки, и в итоге вы получаете: which 'mkdir'>/dev/null 2> echo $ ?; exec 'mkdir' '-p' '/ data/rpmupdate/20130207142923'. Я также хотел бы получить доступ к простой команде exec_. Также отсутствует возможность запуска фоновых задач: 'nohup ./bin/rpmbuildpackages < /dev/null > &/dev/null &'. Например, я генерирую zsh-скрипт (rpmbuildpackages) с использованием шаблона, а затем я просто оставил его на машине. Возможно, умение контролировать такие фоновые задания также было бы неплохо (сохранение PID в ~ ~/.spur). – davidlt

+0

'spur', по-видимому, работает только в системах unix, потому что он имеет зависимость от [' termios'] (http://docs.python.org/2/library/termios.html). Кто-нибудь знает хорошую библиотеку для Windows? – Gabriel

+0

Не совсем верно: если вы используете [предварительно скомпилированный установщик] (http://www.voidspace.org.uk/python/modules.shtml#pycrypto), вы сможете установить paramiko и spur. Я просто сделал это сам ... – ravemir

4

Все уже говорили (рекомендуется) с использованием paramiko и я просто делюсь код питона (API, можно сказать), что позволит Y ou выполнить несколько команд за один раз.

для выполнения команд на различного назначения узла: Commands().run_cmd(host_ip, list_of_commands)

Вы увидите один TODO, который я держал, чтобы остановить выполнение, если какой-либо из команд не в состоянии выполнить, я не знаю, как это сделать Это. пожалуйста, поделитесь своими знаниями

#!/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:]) 

Спасибо!

1

Я рекомендую использовать ssh_decorate

Как просто:

from ssh_decorate import ssh_connect 
ssh=ssh_connect('user','password','server') 

#Run a python function 
@ssh 
def python_pwd(): 
    import os 
    return os.getcwd() 

print (python_pwd()) 

#Run a bash command 
ssh>>"ls" 
+0

это допинг, красиво сделано –

Смежные вопросы