ดำเนินการคำสั่งผ่าน ssh ด้วย Python


145

ฉันกำลังเขียนสคริปต์เพื่อทำให้คำสั่งบรรทัดคำสั่งโดยอัตโนมัติใน Python ในขณะนี้ฉันกำลังโทร:

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

อย่างไรก็ตามฉันต้องเรียกใช้คำสั่งบางอย่างบนเครื่องระยะไกล ด้วยตนเองฉันจะเข้าสู่ระบบโดยใช้ ssh แล้วเรียกใช้คำสั่ง ฉันจะทำให้สิ่งนี้เป็นอัตโนมัติใน Python ได้อย่างไร ฉันจำเป็นต้องเข้าสู่ระบบด้วยรหัสผ่าน (ที่รู้จัก) ไปยังเครื่องระยะไกลดังนั้นฉันจึงไม่สามารถใช้ได้cmd = ssh user@remotehostฉันสงสัยว่ามีโมดูลที่ฉันควรใช้หรือไม่?


คุณเคยดูFabricหรือไม่? ช่วยให้คุณทำสิ่งต่างๆจากระยะไกลผ่าน SSH โดยใช้ python
supersighs

สิ่งนี้ตอบคำถามของคุณหรือไม่? python libraries สำหรับการจัดการ ssh
miken32

คำตอบ:


215

ฉันจะแนะนำคุณให้รู้จักกับparamiko

ดูคำถามนี้

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

3
สมมติฐานที่นี่คือ paramiko มีความปลอดภัยเท่ากับ (open) ssh ใช่ไหม?
user239558

1
จะเกิดอะไรขึ้นถ้ามีการแลกเปลี่ยนคีย์ ssh?
Ardit

22
หากคุณกำลังใช้คีย์ SSH แรกเตรียม keyfile โดยใช้: k = paramiko.RSAKey.from_private_key_file(keyfilename)OR k = paramiko.DSSKey.from_private_key_file(keyfilename)แล้วและในที่สุดssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh..connect(hostname=host, username=user, pkey=k)
Scott Prive

7
ในฐานะผู้ใช้ Paramiko มานาน (แต่ไม่ใช่ผู้เชี่ยวชาญ) ฉันสามารถแนะนำให้ใช้ Paramiko ได้ แต่คุณควรพิจารณากรณีการใช้งานและจำนวนเงินที่คุณต้องการเรียนรู้ Paramiko อยู่ในระดับต่ำมากและคุณสามารถตกหลุมพรางได้อย่างง่ายดายเมื่อคุณสร้าง "command running helper function" โดยไม่เข้าใจโค้ดที่คุณใช้ นั่นหมายความว่าคุณอาจออกแบบว่าสิ่งdef run_cmd(host, cmd):ที่ทำในสิ่งที่คุณต้องการในตอนแรก แต่ความต้องการของคุณมีวิวัฒนาการ คุณต้องเปลี่ยนตัวช่วยสำหรับกรณีการใช้งานใหม่ซึ่งจะเปลี่ยนพฤติกรรมของการใช้งานเดิมที่มีอยู่เดิม วางแผนตามนั้น
Scott Prive

5
สำหรับข้อผิดพลาดของโฮสต์ที่ไม่รู้จักให้ทำ: ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) ก่อน
Nemo

51

หรือคุณสามารถใช้commands.getstatusoutput :

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

ฉันใช้มันอย่างกว้างขวางและได้ผลดี

ใน Python 2.6+ ให้ใช้subprocess.check_output.


5
+1 สำหรับวิธีการในตัวที่เรียบง่าย ในการตั้งค่าปัจจุบันของฉันฉันไม่ต้องการเพิ่มไลบรารี Python ดังนั้นคำแนะนำของคุณจึงมีค่าและตรงไปตรงมามากเช่นกัน
Philip Kearns

3
ตรวจสอบให้แน่ใจว่าโฮสต์ระยะไกลของคุณได้รับการตั้งค่าสำหรับ ssh ที่ไม่มีรหัสผ่านหากไม่เป็นเช่นนั้นคุณต้องทำสิ่งอื่นเพื่อจัดการการตรวจสอบสิทธิ์
powerrox

subprocess.check_output - ทางออกที่ยอดเยี่ยม!
Tim S.

2
@powerrox "สิ่งอื่น ๆ " เหล่านั้นคืออะไร
ealeon

2
@TimS. คุณอาจต้องรวมการจัดการสำหรับการรับรองความถูกต้องด้วยวิธีใดก็ตามที่เหมาะสมกับการตั้งค่าของคุณ ฉันเคยคาดหวังว่าจะป้อนรหัสผ่านที่พรอมต์ มีเธรดนี้พร้อมโซลูชันอื่น ๆ : unix.stackexchange.com/questions/147329/…
powerrox

29

ง่าย ๆ เข้าไว้. ไม่จำเป็นต้องมีไลบรารี

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 แต่จะดีแค่ไหนถ้าเรียกใช้ grep ที่ไหนสักแห่งใน python - คุณทำได้ดี
Ronn Macc

13
หากคำสั่ง ssh ของคุณถามรหัสผ่านคุณจะระบุสิ่งนั้นในไฟล์ Python ได้อย่างไร
BeingSuman

1
@BeingSuman คุณสามารถใช้การตรวจสอบคีย์ SSH สำหรับสิ่งนั้น แม้ว่าฉันเดาว่าคุณคงคิดออกแล้ว
mmrbulbul

20

ฉันพบว่า paramiko มีระดับต่ำเกินไปและ 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ฉันตัดสินใจที่จะลอง คุณสร้างคำสั่งเชลล์เพิ่มเติมและลงท้ายด้วย: ซึ่ง '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
spurtermiosเห็นได้ชัดว่าทำงานได้เฉพาะบนระบบยูนิกซ์ทำให้มันมีการพึ่งพา มีใครรู้จักไลบรารีที่ดีสำหรับ Windows หรือไม่?
Gabriel

ไม่เป็นความจริงทั้งหมด: หากคุณใช้โปรแกรมติดตั้งที่คอมไพล์ไว้ล่วงหน้าคุณจะสามารถติดตั้ง paramiko และ spur ได้ ฉันเพิ่งทำเอง ...
ravemir

@ Gabriel: หนึ่งในรุ่นล่าสุดควรได้รับการปรับปรุงการสนับสนุนบน Windows หากยังใช้งานไม่ได้โปรดเปิดปัญหา
Michael Williamson

@davidlt: เมื่อสร้าง an SshShellตอนนี้มีตัวเลือกในการตั้งค่าประเภทเชลล์ หากใช้เชลล์ขั้นต่ำโดยการส่งผ่านshell_type=spur.ssh.ShellTypes.minimalจะมีการส่งคำสั่งดิบเท่านั้น การใช้งานพื้นหลังทำให้ Spur ไม่ได้อยู่ในขอบเขต แต่คุณควรจะสามารถเรียกใช้คำสั่งที่คุณได้อธิบายไว้โดยการเรียกใช้เชลล์เช่นshell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"])
Michael Williamson

10

ทั้งหมดได้ระบุไว้แล้ว (แนะนำ) โดยใช้paramikoและฉันแค่แชร์รหัส python (API อาจพูดได้) ที่จะช่วยให้คุณดำเนินการหลายคำสั่งในครั้งเดียว

ในการดำเนินการคำสั่งบนโหนดต่างๆให้ใช้: Commands().run_cmd(host_ip, list_of_commands)

คุณจะเห็นสิ่งที่ต้องทำหนึ่งรายการซึ่งฉันเก็บไว้เพื่อหยุดการดำเนินการหากคำสั่งใด ๆ ไม่สามารถดำเนินการได้ฉันไม่รู้ว่าจะทำอย่างไร กรุณาแบ่งปันความรู้ของคุณ

#!/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 (ก็ดีเหมือนกัน) ฉันอยากจะแนะนำอย่างใดอย่างหนึ่ง พวกเขาทำงานแตกต่างกันเล็กน้อย แต่มีการใช้งานที่ทับซ้อนกันค่อนข้างมาก


5
ลิงก์ไปยัง pxssh เป็นการเดินทางย้อนเวลาที่ดี
Oben Sonne

2

ในที่สุด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 แล้ว แหล่งที่มาดั้งเดิมของโซลูชัน: แหล่งที่มา


2

คำตอบที่ยอมรับไม่ได้ผลสำหรับฉันนี่คือสิ่งที่ฉันใช้แทน:

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/issues/11
2. https://stackoverflow.com/a/61016663/797495


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()

0

ดูที่spurplusกระดาษห่อหุ้มที่เราพัฒนาขึ้นspurซึ่งมีคำอธิบายประกอบประเภทและลูกเล่นเล็ก ๆ น้อย ๆ (การเชื่อมต่อ SFTP ใหม่, md5 และอื่น ๆ ): https://pypi.org/project/spurplus/


2
กระดาษห่อหุ้มรอบ ๆ กระดาษห่อ .. สวยดี :)
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
#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

  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()

6
แทนที่จะโพสต์คำตอบของคุณใหม่เมื่อสองวันก่อนด้วยการจัดรูปแบบที่ดีขึ้นทำไมไม่แก้ไขคำตอบเก่าและปรับปรุงการจัดรูปแบบ
snakecharmerb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.