Виконайте команди над ssh за допомогою Python


136

Я пишу сценарій для автоматизації деяких команд командного рядка в Python. На даний момент я телефоную таким чином:

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

Однак мені потрібно запустити кілька команд на віддаленій машині. Вручну я входив би за допомогою ssh, а потім запускав команди. Як би я автоматизував це в Python? Мені потрібно увійти з (відомим) паролем на віддалену машину, тому я не можу просто використовувати cmd = ssh user@remotehost, мені цікаво, чи є модуль, яким я повинен користуватися?

Відповіді:


201

Я віднесу вас до параміко

див. це питання

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

3
Припущення тут полягає в тому, що параміко настільки ж безпечний, як і (відкритий) ssh. Є це?
користувач239558

1
що робити, якщо обміняти ключі ssh?
Ардіт

19
Якщо ви використовуєте ключі SSH, спочатку підготувати файл_ключа з використанням: k = paramiko.RSAKey.from_private_key_file(keyfilename)АБО k = paramiko.DSSKey.from_private_key_file(keyfilename)ТО ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())і , нарешті ssh..connect(hostname=host, username=user, pkey=k).
Скотт-Прі

7
Як давній користувач Paramiko (але не експерт), я можу запропонувати використовувати Paramiko, але ви повинні врахувати ваші випадки використання та те, скільки ви готові дізнатися. Paramiko дуже низького рівня, і ви можете легко потрапити в пастку, де ви створюєте "команду, яка виконує функцію помічника", не повністю розуміючи код, який ви використовуєте. Це означає, що ви можете розробити скажіть, def run_cmd(host, cmd):що робить те, що спочатку хочете, але ваші потреби розвиваються. Ви в остаточному підсумку змінюєте помічник для нового випадку використання, який змінює поведінку старого існуючого використання. Плануйте відповідно.
Скотт Прів

3
Якщо невідома помилка хоста, зробіть: ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) раніше
Немо

49

Або ви можете просто скористатися command.getstatusoutput :

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

Я широко його використовував, і він чудово працює.

У Python 2.6+ використовуйте subprocess.check_output.


4
+1 для приємного простого вбудованого методу. У моїй нинішній програмі я не хочу додавати бібліотеки Python, тому ваша пропозиція цінна, і дуже відверта.
Філіп Кірнс

3
просто переконайтесь, що ваш віддалений хост налаштований на без паролів ssh, якщо ні, вам доведеться робити інші речі для управління автентифікацією
powerrox

subprocess.check_output - чудове рішення!
Тім С.

2
@powerrox, що це за "інші речі?"
ealeon

2
@TimS. можливо, вам доведеться включити обробку для аутентифікації будь-якими способами, що підходять для вашої установки. Я звичайно очікував ввести пароль під запитом. то є ця тема з іншими рішеннями: unix.stackexchange.com/questions/147329/…
powerrox

29

Ви подивилися на Fabric ? Це дозволяє робити всі види віддалених речей через SSH за допомогою python.


18

Я знайшов paramiko бути трохи занадто низького рівня, і тканина не особливо добре підходить для використання в якості бібліотеки, тому я зібрав свою власну бібліотеку під назвою шпори , яка використовує 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. Ви генеруєте додаткові команди оболонки і закінчуєтесь тим, що 'mkdir'> / dev / null 2> & 1; ехо $ ?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'. Я хотів би також мати доступ до рівнини exec_command. Крім того, відсутня можливість виконання фонових завдань: nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. Наприклад, я створюю zsh-скрипт (rpmbuildpackages) за допомогою шаблону, а потім просто залишаю його працювати на машині. Можливо, можливість моніторингу таких фонових завдань також буде непоганою (збереження PID в деяких ~ / .spur).
davidlt

1
spurМабуть, працює тільки на системах Unix, оскільки вона має залежність від termios. Хтось знає хорошу бібліотеку для Windows?
Габріель

Не зовсім вірно: якщо ви будете використовувати попередньо складений інсталятор , ви зможете встановити paramiko та spur. Я щойно це зробив сам ...
ravemir

@Gabriel: одна з останніх версій повинна мати покращену підтримку в Windows. Якщо це все ще не працює, не соромтесь відкривати випуск.
Майкл Вільямсон,

@davidlt: під час створення an SshShell, тепер є можливість встановити тип оболонки. Якщо при введенні використовується мінімальна оболонка shell_type=spur.ssh.ShellTypes.minimal, то надсилається лише необроблена команда. Реалізація фонових завдань безпосередньо відчуває трохи поза сферою для Spur, але ви повинні мати змогу запустити описану вами команду, викликавши оболонку, наприклад shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"]).
Майкл Вільямсон,

18

Не ускладнювати. Бібліотеки не потрібні.

import subprocess

subprocess.Popen("ssh {user}@{host} {cmd}".format(user=user, host=host, cmd='ls -l'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

1
Підпроцес - це ваш швейцарський армійський ніж в автоматизації. Потім ви можете комбінувати Python з нескінченними можливостями, такими як сценарії оболонки, sed, awk, grep. Так, ви все можете зробити в Python, але хіба не було б чудово просто запустити греп десь у python - добре ви можете.
Ронн Макк

12
якщо ваші команди ssh запитують пароль, як би ви вказали це у файлі Python?
БутиSuman

1
@BeingSuman Для цього можна використовувати автентифікацію ключа SSH. Хоча я здогадуюсь, ви вже це зрозуміли.
mmrbulbul

9

Усі вже заявили (рекомендується) за допомогою paramiko, і я просто ділюсь кодом python (API можна сказати), який дозволить вам виконувати кілька команд за один раз.

виконувати команди при використанні різних вузлів: 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:])

Дякую!


4

Я використав параміко купу (приємно) і pxssh (теж приємно). Я б рекомендував будь-яке. Вони працюють трохи інакше, але мають відносно велике перекриття у використанні.


4
Посилання на pxssh - це приємна подорож назад у часі.
Обен Сонне

3

paramiko нарешті працював для мене після додавання додаткового рядка, який є дійсно важливим (рядок 3):

import paramiko

p = paramiko.SSHClient()
p.set_missing_host_key_policy(paramiko.AutoAddPolicy())   # This script doesn't work for me unless this line is added!
p.connect("server", port=22, username="username", password="password")
stdin, stdout, stderr = p.exec_command("your command")
opt = stdout.readlines()
opt = "".join(opt)
print(opt)

Переконайтеся, що встановлений пакет paramiko. Оригінальне джерело рішення: Джерело


1
#Reading the Host,username,password,port from excel file
import paramiko 
import xlrd

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0,1)
Port = int(sheet.cell_value(3,1))
User = sheet.cell_value(1,1)
Pass = sheet.cell_value(2,1)

def details(Host,Port,User,Pass):
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ',Host)
    stdin, stdout, stderr = ssh.exec_command("")
    stdin.write('xcommand SystemUnit Boot Action: Restart\n')
    print('success')

details(Host,Port,User,Pass)

1

Працює чудово ...

import paramiko
import time

ssh = paramiko.SSHClient()
#ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.106.104.24', port=22, username='admin', password='')

time.sleep(5)
print('connected')
stdin, stdout, stderr = ssh.exec_command(" ")

def execute():
       stdin.write('xcommand SystemUnit Boot Action: Restart\n')
       print('success')

execute()

1

Прийнята відповідь не спрацювала для мене, ось що я використав замість цього:

import paramiko
import os

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.load_system_host_keys()
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
ssh.connect("d.d.d.d", username="user", password="pass", port=22222)

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -alrt")
exit_code = ssh_stdout.channel.recv_exit_status() # handles async exit error 

for line in ssh_stdout:
    print(line.strip())

total 44
-rw-r--r--.  1 root root  129 Dec 28  2013 .tcshrc
-rw-r--r--.  1 root root  100 Dec 28  2013 .cshrc
-rw-r--r--.  1 root root  176 Dec 28  2013 .bashrc
...

Крім того, ви можете використовувати sshpass :

import subprocess
cmd = """ sshpass -p "myPas$" ssh user@d.d.d.d -p 22222 'my command; exit' """
print( subprocess.getoutput(cmd) )

Посилання:
1. https://github.com/onyxfish/relay/isissue/11
2. https://stackoverflow.com/a/61016663/797495


0

Погляньте на spurplusобгортку, яку ми розробили навколо, spurяка містить примітки про типи та деякі незначні трюки (підключення SFTP, md5 тощо ): https://pypi.org/project/spurplus/


1
обгортка навколо обгортки навколо обгортки .. приємно :)
Alex R

Що ж, якщо ви хочете зберегти сценарії розгортання тривіальними, я сумніваюся, що основні інструменти є досить простими / абстрактними. Поки ми не спостерігали протікаючих абстракцій.
marko.ristin

0

Попросити користувача ввести команду відповідно до пристрою, на якому він
увійшов. Код нижче наведений на основі PEP8online.com.

import paramiko
import xlrd
import time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0, 1)
Port = int(sheet.cell_value(3, 1))
User = sheet.cell_value(1, 1)
Pass = sheet.cell_value(2, 1)

def details(Host, Port, User, Pass):
    time.sleep(2)
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ', Host)
    stdin, stdout, stderr = ssh.exec_command("")
    x = input('Enter the command:')
    stdin.write(x)
    stdin.write('\n')
    print('success')

details(Host, Port, User, Pass)

0

Нижче наведено приклад, якщо ви хочете, щоб користувальницькі вводили ім'я хоста, ім’я користувача, пароль та номер порту.

  import paramiko

  ssh = paramiko.SSHClient()

  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())



  def details():

  Host = input("Enter the Hostname: ")

  Port = input("Enter the Port: ")

  User = input("Enter the Username: ")

  Pass = input("Enter the Password: ")

  ssh.connect(Host, Port, User, Pass, timeout=2)

  print('connected')

  stdin, stdout, stderr = ssh.exec_command("")

  stdin.write('xcommand SystemUnit Boot Action: Restart\n')

  print('success')

  details()

5
Замість того, щоб повторно відрекомендувати свою відповідь від двох днів тому з кращим форматуванням, чому б не відредагувати старішу відповідь та покращити її форматування?
snakecharmerb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.