Thực hiện các lệnh trên ssh với Python


136

Tôi đang viết một kịch bản để tự động hóa một số lệnh dòng lệnh trong Python. Hiện tại tôi đang thực hiện các cuộc gọi như vậy:

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

Tuy nhiên tôi cần chạy một số lệnh trên máy từ xa. Theo cách thủ công, tôi sẽ đăng nhập bằng ssh và sau đó chạy các lệnh. Làm thế nào tôi có thể tự động hóa điều này trong Python? Tôi cần đăng nhập bằng mật khẩu (đã biết) vào máy từ xa, vì vậy tôi không thể sử dụng cmd = ssh user@remotehost, tôi tự hỏi liệu tôi có nên sử dụng mô-đun không?

Câu trả lời:


201

Tôi sẽ giới thiệu bạn đến paramiko

xem câu hỏi này

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

3
Giả định ở đây là paramiko an toàn như (mở) ssh. Là nó?
user239558 24/2/2015

1
Nếu các phím ssh được trao đổi thì sao?
Ardit

19
Nếu bạn đang sử dụng các khóa SSH, trước tiên hãy chuẩn bị tệp khóa bằng EITHER: k = paramiko.RSAKey.from_private_key_file(keyfilename)HOẶC k = paramiko.DSSKey.from_private_key_file(keyfilename)THÌ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())và cuối cùng ssh..connect(hostname=host, username=user, pkey=k).
Scott Prive

7
Là người dùng Paramiko lâu năm (nhưng không phải là chuyên gia), tôi có thể đề xuất sử dụng Paramiko nhưng bạn nên xem xét các trường hợp sử dụng của mình và mức độ bạn muốn học. Paramiko ở cấp độ rất thấp và bạn có thể dễ dàng rơi vào một cái bẫy nơi bạn tạo ra "chức năng trợ giúp chạy lệnh" mà không hiểu đầy đủ mã bạn đang sử dụng. Điều đó có nghĩa là bạn có thể thiết kế nói rằng def run_cmd(host, cmd):đó là những gì bạn muốn lúc đầu, nhưng nhu cầu của bạn phát triển. Cuối cùng, bạn thay đổi người trợ giúp cho trường hợp sử dụng mới, điều này sẽ thay đổi hành vi của việc sử dụng cũ hơn. Lên kế hoạch phù hợp.
Scott Prive

3
Đối với lỗi máy chủ không xác định, hãy làm: ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) trước
Nemo

48

Hoặc bạn chỉ có thể sử dụng lệnh.getstatusoutput :

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

Tôi đã sử dụng nó rộng rãi và nó hoạt động tuyệt vời.

Trong Python 2.6+, sử dụng subprocess.check_output.


4
+1 cho một phương thức tích hợp đơn giản đẹp. Trong thiết lập hiện tại của tôi, tôi không muốn thêm các thư viện Python để đề xuất của bạn có giá trị, rất đơn giản.
Philip Kearns

3
chỉ cần đảm bảo rằng máy chủ từ xa của bạn được thiết lập cho ssh không mật khẩu, nếu không, bạn phải làm những việc khác để quản lý xác thực
powerrox

sub process.checkDefput - giải pháp tuyệt vời!
Tim S.

2
@powerrox Những "thứ khác là gì?"
ealeon

2
@TimS. bạn có thể phải bao gồm xử lý để xác thực bằng bất kỳ phương tiện nào phù hợp với thiết lập của bạn. Tôi đã sử dụng mong đợi để nhập mật khẩu tại dấu nhắc. sau đó có chủ đề này với các giải pháp khác: unix.stackexchange.com/questions/147329/NH
powerrox

29

Bạn đã có một cái nhìn về vải ? Nó cho phép bạn thực hiện tất cả các loại công cụ từ xa qua SSH bằng python.


18

Tôi thấy paramiko hơi quá thấp và Fabric không đặc biệt phù hợp để sử dụng làm thư viện, vì vậy tôi kết hợp thư viện của riêng mình có tên là spur sử dụng paramiko để thực hiện 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

Nếu bạn cần chạy bên trong một cái vỏ:

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

2
Tôi quyết định thử spur. Bạn tạo các lệnh shell bổ sung và bạn kết thúc bằng: which 'mkdir'> / dev / null 2> & 1; tiếng vang $?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'. Tôi cũng muốn có quyền truy cập vào một đồng bằng exec_command. Cũng thiếu khả năng chạy các tác vụ nền : nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. Ví dụ, tôi tạo một tập lệnh zsh (rpmbuildpackages) bằng cách sử dụng mẫu và sau đó tôi chỉ để nó chạy trên máy. Có thể khả năng giám sát các công việc nền như vậy cũng sẽ rất tốt (tiết kiệm PID trong một số ~ / .spur).
davidlt

1
spurrõ ràng chỉ hoạt động trên các hệ thống unix vì nó có sự phụ thuộc vào termios. Có ai biết một thư viện tốt cho Windows không?
Gabriel

Không hoàn toàn đúng: nếu bạn sử dụng trình cài đặt được biên dịch sẵn , bạn sẽ có thể cài đặt paramiko và spur. Tôi vừa mới làm điều đó ...
ravemir

@Gabriel: một trong những bản phát hành gần đây cần được hỗ trợ cải thiện trên Windows. Nếu nó vẫn không hoạt động, xin vui lòng mở một vấn đề.
Michael Williamson

@davidlt: khi xây dựng một SshShell, bây giờ có tùy chọn để đặt loại vỏ. Nếu một shell tối thiểu được sử dụng bằng cách chuyển vào shell_type=spur.ssh.ShellTypes.minimal, thì chỉ có lệnh thô được gửi. Việc triển khai các tác vụ nền trực tiếp cảm thấy hơi ngoài phạm vi cho Spur, nhưng bạn sẽ có thể chạy lệnh bạn đã mô tả bằng cách gọi shell, ví dụ shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"]).
Michael Williamson

18

Giữ cho nó đơn giản. Không cần thư viện.

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
Sub process là con dao quân đội Thụy Sĩ của bạn trong tự động hóa. Sau đó, bạn có thể kết hợp Python với các khả năng vô tận như shell script, sed, awk, grep. Vâng, tất cả bạn có thể làm trong Python, nhưng sẽ không tuyệt vời gì nếu chỉ chạy một grep ở đâu đó trong python - bạn cũng có thể.
Ronn Macc

11
nếu các lệnh ssh của bạn yêu cầu mật khẩu, làm thế nào bạn cung cấp nó trong tệp Python?
BeingSuman

1
@ByingSuman Bạn có thể sử dụng xác thực khóa SSH cho điều đó. Mặc dù tôi đoán Bạn đã tìm ra điều đó.
mmrbulbul

9

Tất cả đã được tuyên bố (khuyến nghị) bằng cách sử dụng paramiko và tôi chỉ chia sẻ mã python (API có thể nói) sẽ cho phép bạn thực thi nhiều lệnh trong một lần.

để thực hiện các lệnh trên nút khác nhau sử dụng: Commands().run_cmd(host_ip, list_of_commands)

Bạn sẽ thấy một TODO mà tôi đã giữ để dừng thực thi nếu bất kỳ lệnh nào không thực thi, tôi không biết làm thế nào để thực hiện. hãy chia sẻ kiến ​​thức của bạn

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

Cảm ơn bạn!


4

Tôi đã sử dụng paramiko một bó (tốt đẹp) và pxssh (cũng tốt đẹp). Tôi cũng muốn giới thiệu. Chúng hoạt động hơi khác một chút nhưng có sự chồng chéo tương đối lớn trong cách sử dụng.


4
Liên kết đến pxssh là một chuyến đi ngược thời gian.
Oben Sonne

3

paramiko cuối cùng đã làm việc cho tôi sau khi thêm dòng bổ sung, đây là dòng thực sự quan trọng (dòng 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)

Hãy chắc chắn rằng gói paramiko đã được cài đặt. Nguồn gốc của giải pháp: Nguồn


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

Hoạt động hoàn hảo ...

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

Câu trả lời được chấp nhận không hiệu quả với tôi, đây là những gì tôi đã sử dụng thay thế:

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

Ngoài ra, bạn có thể sử dụng sshpass :

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

Tài liệu tham khảo:
1. https://github.com/onyxfish/relay/issues/11
2. https://stackoverflow.com/a/61016663/797495


0

Hãy xem spurplus, một trình bao bọc chúng tôi đã phát triển xung quanh spurcung cấp chú thích loại và một số mánh lới quảng cáo nhỏ (kết nối lại SFTP, md5, v.v. ): https://pypi.org/project/spurplus/


1
một trình bao bọc xung quanh một trình bao bọc xung quanh một trình bao bọc .. tốt đẹp :)
Alex R

Chà, nếu bạn muốn giữ các kịch bản triển khai của mình tầm thường, tôi nghi ngờ rằng các công cụ cơ bản là đủ đơn giản / trừu tượng. Cho đến nay, chúng tôi đã không quan sát trừu tượng rò rỉ.
marko.ristin

0

Yêu cầu Người dùng nhập lệnh theo thiết bị họ đang đăng nhập.
Mã dưới đây được PEP8online.com xác thực.

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

Ví dụ bên dưới, nếu bạn muốn người dùng nhập tên máy chủ, tên người dùng, mật khẩu và cổng số.

  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
Thay vì đăng lại câu trả lời của bạn từ hai ngày trước với định dạng tốt hơn, tại sao không chỉnh sửa câu trả lời cũ hơn và cải thiện định dạng của nó?
snakecharmerb
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.