Cách đơn giản nhất để SSH bằng Python là gì?


82

Làm cách nào để tôi có thể chỉ cần SSH tới máy chủ từ xa từ tập lệnh Python (3.0) cục bộ, cung cấp thông tin đăng nhập / mật khẩu, thực thi lệnh và in kết quả ra bảng điều khiển Python?

Tôi không muốn sử dụng bất kỳ thư viện lớn bên ngoài nào hoặc cài đặt bất kỳ thứ gì trên máy chủ từ xa.

Câu trả lời:


42

Tôi chưa thử, nhưng mô-đun pysftp này có thể hữu ích, từ đó sử dụng paramiko. Tôi tin rằng mọi thứ đều ở phía khách hàng.

Lệnh thú vị có lẽ là lệnh .execute()thực thi một lệnh tùy ý trên máy từ xa. (Mô-đun cũng có các tính năng .get().putphương thức ám chỉ nhiều hơn đến ký tự FTP của nó).

CẬP NHẬT:

Tôi đã viết lại câu trả lời sau khi bài đăng trên blog mà tôi liên kết ban đầu không còn nữa. Một số nhận xét đề cập đến phiên bản cũ của câu trả lời này giờ sẽ trông kỳ lạ.


Tốt tìm thấy! Miễn là bạn không quan tâm đến việc tùy chỉnh phản hồi lỗi, phần trừu tượng bổ sung này sẽ rất hữu ích.
Cascabel

Mô-đun ssh đã thực hiện thủ thuật. Đơn giản và hoạt động tốt. Không cần tìm kiếm thông qua API Paramiko.
Christopher Tokar

2
Các liên kết đến tập tin ssh.py bên trong liên kết mà bạn đưa ra là bị hỏng: /
dgorissen

Vâng, chúng tôi có thể có một liên kết mới không. Tôi đã tìm thấy ssh.py trên github, nhưng nó không giống nhau (và không tốt bằng)
joedborg

1
Gói pysftp chỉ cung cấp SFTP. Khác xa với một khách hàng SSH.
bortzmeyer

61

Bạn có thể tự viết mã bằng Paramiko, như đã đề xuất ở trên. Ngoài ra, bạn có thể xem xét Fabric, một ứng dụng python để thực hiện tất cả những điều bạn yêu cầu:

Fabric là một thư viện Python và công cụ dòng lệnh được thiết kế để hợp lý hóa việc triển khai các ứng dụng hoặc thực hiện các tác vụ quản trị hệ thống thông qua giao thức SSH. Nó cung cấp các công cụ để chạy các lệnh shell tùy ý (với tư cách là người dùng đăng nhập bình thường hoặc thông qua sudo), tải lên và tải xuống tệp, v.v.

Tôi nghĩ rằng điều này phù hợp với nhu cầu của bạn. Nó cũng không phải là một thư viện lớn và không yêu cầu cài đặt máy chủ, mặc dù nó có phụ thuộc vào paramiko và pycrypt yêu cầu cài đặt trên máy khách.

Ứng dụng đã từng ở đây . Nó bây giờ có thể được tìm thấy ở đây .

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

Có một số bài báo hay về nó, tuy nhiên bạn nên cẩn thận vì nó đã thay đổi trong sáu tháng qua:

Triển khai Django với Vải

Công cụ của Hacker Python hiện đại: Virtualenv, Fabric và Pip

Triển khai đơn giản và dễ dàng với Fabric và Virtualenv


Sau này: Vải không còn yêu cầu cài đặt paramiko nữa:

$ 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...

Tuy nhiên, điều này chủ yếu là thẩm mỹ: ssh là một nhánh của paramiko, người bảo trì cho cả hai thư viện đều giống nhau (Jeff Forcier, cũng là tác giả của Fabric), và người duy trì có kế hoạch tái hợp paramiko và ssh dưới tên paramiko . (Sự điều chỉnh này thông qua pbanka .)


Vì đây có vẻ là một liên kết thú vị, tôi muốn cập nhật nó vì liên kết của bạn hiện đã bị hỏng. vui lòng sử dụng: clemesha.org/blog/…
dlewin

Người hỏi đã không nói rõ rằng anh ta không muốn sử dụng "thư viện lớn bên ngoài" sao? Paramiko và Fabric đều quá mức cần thiết khi tất cả những gì tác giả thực sự yêu cầu là một công thức ssh đơn giản.
Zoran Pavlovic

1
@Zoran Pavlovic: tất cả các câu trả lời đều là cài đặt gói cục bộ (paramiko, vải, ssh, libssh2) hoặc sử dụng quy trình con để chạy ssh. Giải pháp thứ hai là giải pháp không cần cài đặt, nhưng tôi không nghĩ việc tạo ssh là một ý tưởng tuyệt vời, và OP cũng vậy vì anh ấy đã chọn câu trả lời là cài đặt mô-đun ssh. Các tài liệu đó cho biết: "ssh.py cung cấp ba thao tác SSH phổ biến, lấy, đặt và thực thi. Đây là phần trừu tượng cấp cao dựa trên Paramiko." Vì vậy, trừ khi bạn ủng hộ libssh2, vốn nặng về mã hóa, không có khuyến nghị phù hợp. Tôi ủng hộ đưa ra một giải pháp tốt khi các điều kiện của OP không thể được đáp ứng một cách hợp lý.
hughdbrown

24

Nếu bạn muốn tránh bất kỳ mô-đun thừa nào, bạn có thể sử dụng mô-đun quy trình con để chạy

ssh [host] [command]

và nắm bắt đầu ra.

Hãy thử một cái gì đó như:

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

Để xử lý tên người dùng và mật khẩu, bạn có thể sử dụng quy trình phụ để tương tác với quy trình ssh hoặc bạn có thể cài đặt khóa công khai trên máy chủ để tránh lời nhắc mật khẩu.


7
Nhưng nếu máy khách trên Windows thì sao?
Nathan

Có thể khó cung cấp mật khẩu để xử lý sshcon qua đường ống. Xem Tại sao không chỉ sử dụng một đường ống (popen ())? . Bạn có thể cần pty, pexpectmô-đun để workaround nó.
jfs

dường như không hoạt động đối với một số máy tính ssh của chuỗi; python -c "import numpy; print numpy .__ version__" 'nó nói rằng nó không biết lệnh "import"
usethedeathstar

1
@usethedeathstar: đặt toàn bộ lệnh từ xa trong dấu ngoặc kép: ssh somecomputer 'python -c "import this; in this"'
Neil

17

Tôi đã viết các liên kết Python cho libssh2 . Libssh2 là một thư viện phía máy khách triển khai giao thức 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
Nó có vẻ rất thấp. Ví dụ (ví dụ của riêng bạn), bạn phải nói rõ ràng rằng bạn sử dụng IPv4 hoặc IPv6 (điều gì đó bạn không cần phải làm với ứng dụng dòng lệnh OpenSSH). Ngoài ra, tôi không tìm thấy cách làm cho nó hoạt động với ssh-agent.
bortzmeyer

2
Điều tốt về pylibssh2 là nó truyền tệp WAY nhanh hơn bất kỳ triển khai python gốc nào của ssh như paramiko.
Damien

8

Định nghĩa của bạn về "đơn giản nhất" rất quan trọng ở đây - mã đơn giản có nghĩa là sử dụng một mô-đun (mặc dù "thư viện bên ngoài lớn" là một sự phóng đại).

Tôi tin rằng mô-đun cập nhật nhất (được phát triển tích cực) là paramiko . Nó đi kèm với các tập lệnh demo trong bản tải xuống và có tài liệu API trực tuyến chi tiết. Bạn cũng có thể thử PxSSH , được chứa trong pexpect . Có một mẫu ngắn cùng với tài liệu ở liên kết đầu tiên.

Một lần nữa liên quan đến sự đơn giản, hãy lưu ý rằng khả năng phát hiện lỗi tốt luôn làm cho mã của bạn trông phức tạp hơn, nhưng bạn sẽ có thể sử dụng lại rất nhiều mã từ các tập lệnh mẫu sau đó hãy quên nó đi.


6

Giống như hughdbrown, tôi thích Vải. Xin lưu ý rằng trong khi nó triển khai tập lệnh khai báo của riêng mình (để thực hiện triển khai và tương tự), nó cũng có thể được nhập dưới dạng mô-đun Python và được sử dụng trên các chương trình của bạn mà không cần phải viết tập lệnh Fabric.

Vải có một người bảo trì mới và đang trong quá trình làm lại; điều đó có nghĩa là hầu hết các hướng dẫn bạn (hiện tại) tìm thấy trên web sẽ không hoạt động với phiên bản hiện tại. Ngoài ra, Google vẫn hiển thị trang Vải cũ ở kết quả đầu tiên.

Để có tài liệu cập nhật, bạn có thể kiểm tra: http://docs.fabfile.org


Vải sử dụng một nhánh của paramiko pypi.python.org/pypi/ssh cho tất cả nội dung ssh.
Damien

6

Tôi nhận thấy paramiko ở cấp độ hơi quá thấp và Fabric không đặc biệt thích hợp để sử dụng làm thư viện, vì vậy tôi đã tập hợp thư viện của riêng mình có tên là spur sử dụng paramiko để triển khai giao diện đẹp hơn một chút:

import spur

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

Bạn cũng có thể chọn in đầu ra của chương trình khi chương trình đang chạy, điều này rất hữu ích nếu bạn muốn xem đầu ra của các lệnh chạy dài trước khi nó thoát ra:

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

Không hỗ trợ chạy các lệnh không chuẩn, ví dụ: trên một số bộ định tuyến (MikroTik) lệnh có tiền tố là '/', thư viện này sẽ báo lỗi. Tuy nhiên, đối với các máy chủ Linux tiêu chuẩn, nó có vẻ khá tốt.
Babken Vardanyan,

Khi tôi chuyển một địa chỉ IP cho tên máy chủ, nó gặp lỗi thông báo rằng không tìm thấy IP trong known_hosts ...
rexbelia

@rexbelia Đây là hành vi bình thường của SSH: để đảm bảo rằng bạn đang nói chuyện với đúng máy chủ, SSH sẽ chỉ chấp nhận khóa từ máy chủ nếu nó đã được biết. Giải pháp là thêm khóa có liên quan vào known_hosts hoặc đặt đối số thiếu_host_key thành một giá trị thích hợp, như được mô tả trong tài liệu.
Michael Williamson

4

Vì lợi ích của những người truy cập vào đây, hãy tìm kiếm mẫu python ssh. Câu hỏi và câu trả lời ban đầu bây giờ gần như là một giải mã cũ. Có vẻ như paramiko đã đạt được một chút chức năng (Ok. Tôi thừa nhận - đoán thuần túy ở đây - tôi mới làm quen với Python) và bạn có thể tạo ứng dụng ssh trực tiếp với 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()

Mã này được chuyển thể từ bản demo của https://github.com/paramiko/paramiko Nó hoạt động cho tôi.


1

Điều này đã làm việc cho tôi

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

Hãy xem spurplus , một lớp bao bọc xung quanh spurparamiko mà chúng tôi đã phát triển để quản lý các máy từ xa và thực hiện các thao tác với tệp.

Spurplus cung cấp một check_output()chức năng ngoài hộp:

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.