Jaki jest najprostszy sposób na SSH przy użyciu Pythona?


82

Jak mogę po prostu SSH do zdalnego serwera z lokalnego skryptu Python (3.0), podać login / hasło, wykonać polecenie i wydrukować dane wyjściowe do konsoli Pythona?

Wolałbym nie używać żadnej dużej biblioteki zewnętrznej ani niczego instalować na zdalnym serwerze.

Odpowiedzi:


42

Nie próbowałem tego, ale ten moduł pysftp może pomóc, który z kolei używa paramiko. Uważam, że wszystko jest po stronie klienta.

Interesującym poleceniem jest prawdopodobnie .execute()wykonanie dowolnego polecenia na zdalnym komputerze. (Moduł posiada również funkcje .get()i .putmetody, które bardziej nawiązują do jego charakteru FTP).

AKTUALIZACJA:

Ponownie napisałem odpowiedź po tym, jak post na blogu, do którego pierwotnie utworzyłem link, nie jest już dostępny. Niektóre komentarze odnoszące się do starej wersji tej odpowiedzi będą teraz wyglądać dziwnie.


Dobre znalezisko! Dopóki nie zależy ci na dostosowywaniu odpowiedzi na błędy, ta dodatkowa abstrakcja byłaby bardzo przydatna.
Cascabel

Moduł ssh załatwił sprawę. Proste i działa dobrze. Brak przeszukiwania interfejsu API Paramiko.
Christopher Tokar

2
Link do pliku ssh.py wewnątrz podanego linku jest uszkodzony: /
dgorissen

Tak, możemy prosić o nowy link. Znalazłem ssh.py na githubie, ale to nie to samo (i nie tak dobre)
joedborg

1
Pakiet pysftp zapewnia tylko SFTP. Daleko od klienta SSH.
bortzmeyer

61

Możesz to samemu zakodować za pomocą Paramiko, jak zasugerowano powyżej. Możesz też zajrzeć do Fabric, aplikacji w języku Python, w której możesz wykonywać wszystkie pytania, o które pytasz:

Fabric to biblioteka języka Python i narzędzie wiersza poleceń zaprojektowane w celu usprawnienia wdrażania aplikacji lub wykonywania zadań administracyjnych systemu za pośrednictwem protokołu SSH. Zapewnia narzędzia do uruchamiania dowolnych poleceń powłoki (jako zwykły użytkownik logowania lub przez sudo), wysyłania i pobierania plików i tak dalej.

Myślę, że to pasuje do twoich potrzeb. Nie jest to również duża biblioteka i nie wymaga instalacji serwera, chociaż ma zależności od paramiko i pycrypt, które wymagają instalacji na kliencie.

Aplikacja była tutaj . Można go teraz znaleźć tutaj .

* The official, canonical repository is git.fabfile.org
* The official Github mirror is GitHub/bitprophet/fabric

Jest na ten temat kilka dobrych artykułów, ale należy zachować ostrożność, ponieważ zmienił się w ciągu ostatnich sześciu miesięcy:

Wdrażanie Django w Fabric

Narzędzia współczesnego hakera Pythona: Virtualenv, Fabric i Pip

Proste i łatwe wdrożenie dzięki Fabric i Virtualenv


Później: Tkanina nie wymaga już instalacji paramiko:

$ pip install fabric
Downloading/unpacking fabric
  Downloading Fabric-1.4.2.tar.gz (182Kb): 182Kb downloaded
  Running setup.py egg_info for package fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
Downloading/unpacking ssh>=1.7.14 (from fabric)
  Downloading ssh-1.7.14.tar.gz (794Kb): 794Kb downloaded
  Running setup.py egg_info for package ssh
Downloading/unpacking pycrypto>=2.1,!=2.4 (from ssh>=1.7.14->fabric)
  Downloading pycrypto-2.6.tar.gz (443Kb): 443Kb downloaded
  Running setup.py egg_info for package pycrypto
Installing collected packages: fabric, ssh, pycrypto
  Running setup.py install for fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
    Installing fab script to /home/hbrown/.virtualenvs/fabric-test/bin
  Running setup.py install for ssh
  Running setup.py install for pycrypto
...
Successfully installed fabric ssh pycrypto
Cleaning up...

Jest to jednak głównie kosmetyczne: ssh to rozwidlenie paramiko, opiekun obu bibliotek jest ten sam (Jeff Forcier, również autor Fabric), a opiekun planuje ponownie połączyć paramiko i ssh pod nazwą paramiko . (Ta korekta przez pbanka .)


Ponieważ wydaje się to interesującym linkiem, chciałbym go zaktualizować, ponieważ Twój jest teraz uszkodzony. użyj: clemesha.org/blog/…
dlewin

Czy pytający nie wskazał, że nie chce używać „dużej biblioteki zewnętrznej”? Paramiko i Fabric są przesadą, gdy autor naprawdę poprosił o prosty, jednorazowy przepis na ssh.
Zoran Pavlovic

1
@Zoran Pavlovic: wszystkie odpowiedzi dotyczyły albo zainstalowania lokalnego pakietu (paramiko, fabric, ssh, libssh2), albo użycia podprocesu do uruchomienia ssh. To drugie rozwiązanie nie wymaga instalacji, ale nie sądzę, aby tworzenie ssh było dobrym pomysłem, podobnie jak OP, ponieważ wybrał odpowiedź, aby zainstalować moduł ssh. Ci doktorzy mówią: „ssh.py udostępnia trzy typowe operacje SSH: pobierz, umieść i wykonaj. Jest to abstrakcja wysokiego poziomu dla Paramiko”. Więc jeśli nie wolisz biblioteki libssh2, która jest obciążona kodowaniem, nie ma zgodnych zaleceń. Jestem zwolennikiem podania dobrego rozwiązania, gdy nie można w racjonalny sposób spełnić warunków PO.
hughdbrown

24

Jeśli chcesz uniknąć dodatkowych modułów, możesz uruchomić moduł podprocesu

ssh [host] [command]

i przechwyć wynik.

Spróbuj czegoś takiego:

process = subprocess.Popen("ssh example.com ls", shell=True,
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output,stderr = process.communicate()
status = process.poll()
print output

Aby radzić sobie z nazwami użytkowników i hasłami, możesz użyć podprocesu do interakcji z procesem ssh lub możesz zainstalować klucz publiczny na serwerze, aby uniknąć pytania o hasło.


7
Ale co, jeśli klient jest w systemie Windows?
Nathan,

sshPodanie hasła do podprocesu za pośrednictwem potoku może być trudne . Zobacz Dlaczego po prostu nie użyć potoku (popen ())? . Może być konieczne pty, pexpectmoduły, aby go obejść.
jfs

wydaje się, że nie działa na jakimś komputerze z ciągiem ssh; python -c "import numpy; print numpy .__ version__" 'mówi, że nie zna polecenia "import"
użyjeathstar

1
@usethedeathstar: zawiń całe zdalne polecenie w cudzysłów: ssh jakiś komputer 'python -c "zaimportuj to; wydrukuj to"'
Neil

17

Napisałem powiązania Pythona dla libssh2 . Libssh2 to biblioteka po stronie klienta implementująca protokół SSH2.

import socket
import libssh2

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('exmaple.com', 22))

session = libssh2.Session()
session.startup(sock)
session.userauth_password('john', '******')

channel = session.channel()
channel.execute('ls -l')

print channel.read(1024)

2
Wydaje się, że jest to bardzo niski poziom. Na przykład (Twój własny przykład) musisz wyraźnie powiedzieć, że używasz IPv4 lub IPv6 (coś, czego nie musisz robić z klientem wiersza poleceń OpenSSH). Nie znalazłem również sposobu, aby to działało z ssh-agent.
bortzmeyer

2
Zaletą pylibssh2 jest to, że przesyła pliki DUŻO szybciej niż jakakolwiek natywna implementacja ssh w Pythonie, taka jak paramiko.
Damien

8

Twoja definicja „najprostszego” jest tutaj ważna - prosty kod oznacza użycie modułu (choć „duża biblioteka zewnętrzna” to przesada).

Uważam, że najbardziej aktualnym (aktywnie rozwijanym) modułem jest paramiko . Zawiera skrypty demonstracyjne do pobrania i szczegółową dokumentację interfejsu API online. Możesz także wypróbować PxSSH , który jest zawarty w pexpect . Pod pierwszym linkiem znajduje się krótka próbka wraz z dokumentacją.

Ponownie, jeśli chodzi o prostotę, pamiętaj, że dobre wykrywanie błędów zawsze sprawi, że Twój kod będzie wyglądał na bardziej złożony, ale powinieneś być w stanie ponownie użyć dużej ilości kodu z przykładowych skryptów, a następnie zapomnieć o tym.


6

Podobnie jak Hughdbrown, lubię Fabric. Zauważ, że chociaż implementuje własne deklaratywne skrypty (do tworzenia wdrożeń itp.), Może być również importowane jako moduł Pythona i używane w twoich programach bez konieczności pisania skryptu Fabric.

Tkanina ma nowego opiekuna i jest w trakcie przepisywania; oznacza to, że większość samouczków, które (obecnie) znajdziesz w sieci, nie będzie działać z aktualną wersją. Ponadto Google nadal wyświetla starą stronę Fabric jako pierwszy wynik.

Aktualną dokumentację można znaleźć pod adresem : http://docs.fabfile.org


Fabric używa rozwidlenia paramiko pypi.python.org/pypi/ssh dla wszystkich rzeczy ssh.
Damien

6

Uważam, że paramiko jest trochę za niskopoziomowe, a Fabric nie jest specjalnie przystosowany do użycia jako biblioteka, więc stworzyłem własną bibliotekę o nazwie spur, która używa paramiko do zaimplementowania nieco ładniejszego interfejsu:

import spur

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

Możesz także wydrukować dane wyjściowe programu w trakcie jego działania, co jest przydatne, jeśli chcesz zobaczyć wynik długotrwałych poleceń przed jego zakończeniem:

result = shell.run(["echo", "-n", "hello"], stdout=sys.stdout)

Nie obsługuje uruchamiania niestandardowych poleceń, na przykład na niektórych routerach (MikroTik) polecenia są poprzedzone prefiksem '/', ta biblioteka generuje błąd. Jednak dla standardowych hostów linuxowych wygląda to całkiem nieźle.
Babken Vardanyan

Kiedy przekazuję adres IP do nazwy hosta, wyświetla błąd informujący, że adres IP nie został znaleziony w
znanych_hostach

@rexbelia Jest to normalne zachowanie SSH: aby upewnić się, że rozmawiasz z właściwym serwerem, SSH zaakceptuje klucz z hosta tylko wtedy, gdy jest już znany. Rozwiązaniem jest dodanie odpowiedniego klucza do known_hosts lub ustawienie argumentu missing_host_key na odpowiednią wartość, zgodnie z opisem w dokumentacji.
Michael Williamson

4

Z korzyścią dla tych, którzy sięgają tutaj, szukając próbki Pythona ssh. Oryginalne pytanie i odpowiedź są teraz prawie nieaktualne. Wygląda na to, że paramiko zyskało trochę funkcjonalności (ok. Przyznaję - tu zgaduję - jestem nowy w Pythonie) i można stworzyć klienta ssh bezpośrednio z paramiko.

import base64
import paramiko

client = paramiko.SSHClient()

client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.1.1', username='user', password='password')
stdin, stdout, stderr = client.exec_command('cat /proc/meminfo')
for line in stdout:
    print('... ' + line.strip('\n'))
client.close()

Ten kod został zaadaptowany z wersji demonstracyjnej https://github.com/paramiko/paramiko . U mnie działa.


1

To zadziałało dla mnie

import subprocess
import sys
HOST="IP"
COMMAND="ifconfig"

def passwordless_ssh(HOST):
        ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
                       shell=False,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE)
        result = ssh.stdout.readlines()
        if result == []:
                error = ssh.stderr.readlines()
                print >>sys.stderr, "ERROR: %s" % error
                return "error"
        else:
                return result

1

please refer to paramiko.org, its very useful while doing ssh using python.

import paramiko

import time

ssh = paramiko.SSHClient() #SSHClient() is the paramiko object</n>

#Below lines adds the server key automatically to know_hosts file.use anyone one of the below

ssh.load_system_host_keys() 

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:

#Here we are actually connecting to the server.

ssh.connect('10.106.104.24', port=22, username='admin', password='')

time.sleep(5)

#I have mentioned time because some servers or endpoint prints there own information after 
#loggin in e.g. the version, model and uptime information, so its better to give some time 
#before executing the command.

#Here we execute the command, stdin for input, stdout for output, stderr for error

stdin, stdout, stderr = ssh.exec_command('xstatus Time')

#Here we are reading the lines from output.

output = stdout.readlines() 

print(output)


#Below all are the Exception handled by paramiko while ssh. Refer to paramiko.org for more information about exception.


except (BadHostKeyException, AuthenticationException,  
    SSHException, socket.error) as e:           

print(e)

0

Spójrz na spurplus , opakowanie spur i paramiko , które opracowaliśmy do zarządzania zdalnymi maszynami i wykonywania operacji na plikach.

Spurplus zapewnia check_output()funkcję od razu po wyjęciu z pudełka:

import spurplus
with spurplus.connect_with_retries(
        hostname='some-machine.example.com', username='devop') as shell:
     out = shell.check_output(['/path/to/the/command', '--some_argument']) 
     print(out)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.