Lakukan perintah over ssh dengan Python

136

Saya sedang menulis skrip untuk mengotomatisasi beberapa perintah baris perintah dengan Python. Saat ini saya sedang melakukan panggilan:

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

Namun saya perlu menjalankan beberapa perintah pada mesin jarak jauh. Secara manual, saya akan masuk menggunakan ssh dan kemudian menjalankan perintah. Bagaimana saya mengotomatisasi ini dengan Python? Saya perlu masuk dengan kata sandi (dikenal) ke mesin jarak jauh, jadi saya tidak bisa hanya menggunakan cmd = ssh user@remotehost, saya ingin tahu apakah ada modul yang harus saya gunakan?

fredley
sumber

Jawaban:

201

Saya akan merujuk Anda ke paramiko

lihat pertanyaan ini

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd_to_execute)
Shahjapan
sumber
3
Asumsinya di sini adalah bahwa paramiko seaman (terbuka) ssh. Apakah itu?
user239558
1
bagaimana jika kunci ssh dipertukarkan?
Ardit
19
Jika Anda menggunakan kunci SSH, pertama-tama persiapkan keyfile menggunakan EITHER: k = paramiko.RSAKey.from_private_key_file(keyfilename)ATAU k = paramiko.DSSKey.from_private_key_file(keyfilename)KEMUDIAN ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())dan akhirnya ssh..connect(hostname=host, username=user, pkey=k).
Scott Prive
7
Sebagai pengguna lama Paramiko (tetapi bukan ahli), saya dapat menyarankan menggunakan Paramiko tetapi Anda harus mempertimbangkan kasus penggunaan Anda dan seberapa banyak Anda bersedia untuk belajar. Paramiko adalah level yang sangat rendah, dan Anda dapat dengan mudah jatuh ke dalam perangkap di mana Anda membuat "perintah menjalankan fungsi pembantu" tanpa sepenuhnya memahami kode yang Anda gunakan. Itu berarti Anda dapat merancang kata def run_cmd(host, cmd):yang melakukan apa yang Anda inginkan pada awalnya, tetapi kebutuhan Anda berkembang. Anda akhirnya mengubah helper untuk use case baru, yang mengubah perilaku penggunaan lama yang sudah ada. Rencanakan dengan tepat.
Scott Prive
3
Untuk kesalahan host yang tidak dikenal, lakukan: ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) sebelum
Nemo
49

Atau Anda bisa menggunakan command.getstatusoutput :

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

Saya menggunakannya secara luas dan bekerja sangat baik.

Dalam Python 2.6+, gunakan subprocess.check_output.

powerrox
sumber
4
+1 untuk metode bawaan sederhana yang bagus. Dalam pengaturan saya saat ini, saya tidak ingin menambahkan pustaka Python sehingga saran Anda sangat berharga, sangat mudah juga.
Philip Kearns
3
pastikan host jarak jauh Anda sudah diatur untuk ssh tanpa kata sandi, jika tidak, Anda harus melakukan hal lain untuk mengelola otentikasi
powerrox
subprocess.check_output - solusi hebat!
Tim S.
2
@ powerrox apa itu "hal-hal lain?"
ealeon
2
@TIM. Anda mungkin harus memasukkan penanganan untuk otentikasi dengan cara apa pun yang sesuai untuk pengaturan Anda. Saya dulu berharap untuk memasukkan kata sandi saat diminta. kemudian ada utas ini dengan solusi lain: unix.stackexchange.com/questions/147329/…
powerrox
29

Pernahkah Anda melihat Fabric ? Hal ini memungkinkan Anda untuk melakukan segala macam hal jarak jauh melalui SSH menggunakan python.

supersigh
sumber
18

Saya menemukan paramiko agak terlalu rendah, dan Fabric tidak terlalu cocok untuk digunakan sebagai perpustakaan, jadi saya mengumpulkan perpustakaan saya sendiri yang disebut spur yang menggunakan paramiko untuk mengimplementasikan antarmuka yang sedikit lebih bagus:

import spur

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

Jika Anda perlu menjalankan di dalam shell:

shell.run(["sh", "-c", "echo -n hello"])
Michael Williamson
sumber
2
Saya memutuskan untuk mencoba spur. Anda menghasilkan perintah shell tambahan dan Anda berakhir dengan: which 'mkdir'> / dev / null 2> & 1; echo $?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'. Saya juga ingin memiliki akses ke dataran exec_command. Juga hilang kemampuan untuk menjalankan tugas latar belakang: nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. Misalnya, saya membuat skrip zsh (rpmbuildpackages) menggunakan templat dan kemudian saya membiarkannya berjalan di mesin. Mungkin kemampuan untuk memantau pekerjaan latar belakang seperti itu juga akan menyenangkan (menyimpan PID dalam beberapa ~ / .spur).
davidlt
1
spurrupanya hanya berfungsi pada sistem unix karena memiliki ketergantungan pada termios. Adakah yang tahu perpustakaan yang bagus untuk Windows?
Gabriel
Tidak sepenuhnya benar: jika Anda menggunakan installer yang telah dikompilasi , Anda akan dapat menginstal paramiko dan memacu. Saya hanya melakukannya sendiri ...
ravemir
@Gabriel: salah satu rilis terbaru harusnya meningkatkan dukungan pada Windows. Jika masih tidak berfungsi, jangan ragu untuk membuka masalah.
Michael Williamson
@davidlt: saat membuat SshShell, sekarang ada opsi untuk mengatur tipe shell. Jika shell minimal digunakan dengan melewati shell_type=spur.ssh.ShellTypes.minimal, maka hanya perintah mentah yang dikirim. Menerapkan tugas-tugas latar belakang secara langsung terasa agak keluar dari ruang lingkup untuk Spur, tetapi Anda harus dapat menjalankan perintah yang telah Anda jelaskan dengan menggunakan shell misalnya shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"]).
Michael Williamson
18

Tetap sederhana. Tidak diperlukan perpustakaan.

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()
Ronn Macc
sumber
1
Subprocess adalah pisau tentara swiss Anda dalam otomatisasi. Anda kemudian dapat menggabungkan Python dengan kemungkinan tanpa akhir seperti skrip shell, sed, awk, grep. Ya, Anda semua dapat melakukannya dengan Python, tetapi tidakkah lebih baik menjalankan grep di suatu tempat dengan python - yah Anda bisa.
Ronn Macc
12
jika perintah ssh Anda meminta kata sandi, bagaimana Anda menyediakannya dalam file Python?
BeingSuman
1
@BeingSuman Anda dapat menggunakan otentikasi kunci SSH untuk itu. Meskipun saya kira Anda sudah tahu itu.
mmrbulbul
9

Semua sudah menyatakan (disarankan) menggunakan paramiko dan saya hanya berbagi kode python (API satu dapat mengatakan) yang akan memungkinkan Anda untuk menjalankan beberapa perintah sekaligus.

untuk mengeksekusi perintah pada penggunaan simpul yang berbeda: Commands().run_cmd(host_ip, list_of_commands)

Anda akan melihat satu TODO, yang saya simpan untuk menghentikan eksekusi jika ada perintah yang gagal dieksekusi, saya tidak tahu bagaimana cara melakukannya. tolong bagikan pengetahuan Anda

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

Terima kasih!

IAmSurajBobade
sumber
4

Saya telah menggunakan paramiko banyak (bagus) dan pxssh (juga bagus). Saya akan merekomendasikan. Mereka bekerja sedikit berbeda tetapi memiliki tumpang tindih yang relatif besar dalam penggunaannya.

Eric Snow
sumber
4
Tautan ke pxssh adalah perjalanan yang menyenangkan di masa lalu.
Oben Sonne
3

paramiko akhirnya bekerja untuk saya setelah menambahkan baris tambahan, yang sangat penting (baris 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)

Pastikan paket paramiko diinstal. Sumber asli solusinya: Sumber

Alexander Tereshkov
sumber
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)
Harshan Gowda
sumber
1

Bekerja dengan Sempurna ...

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()
Harshan Gowda
sumber
1

Jawaban yang diterima tidak berhasil untuk saya, inilah yang saya gunakan sebagai gantinya:

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

Atau, Anda dapat menggunakan sshpass :

import subprocess
cmd = """ sshpass -p "myPas$" ssh [email protected] -p 22222 'my command; exit' """
print( subprocess.getoutput(cmd) )

Referensi:
1. https://github.com/onyxfish/relay/issues/11
2. https://stackoverflow.com/a/61016663/797495

HUBUNGI19
sumber
0

Lihat spurplus, bungkus yang kami kembangkan spuryang menyediakan anotasi jenis dan beberapa tipuan kecil (menghubungkan kembali SFTP, md5 dll .): Https://pypi.org/project/spurplus/

marko.ristin
sumber
1
bungkus bungkus bungkus bungkus .. bagus :)
Alex R
Nah, jika Anda ingin menyimpan skrip penempatan Anda sepele, saya ragu bahwa alat yang mendasarinya cukup sederhana / abstrak. Sejauh ini, kami tidak mengamati abstraksi bocor.
marko.ristin
0

Meminta Pengguna untuk memasukkan perintah sesuai perangkat tempat mereka masuk.
Kode di bawah ini divalidasi oleh 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)
Harshan Gowda
sumber
0

Contoh di bawah ini, hapus jika Anda ingin input pengguna untuk nama host, nama pengguna, kata sandi dan nomor port.

  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()
Harshan Gowda
sumber
5
Daripada memposting ulang jawaban Anda dari dua hari lalu dengan format yang lebih baik, mengapa tidak mengedit jawaban yang lebih lama dan meningkatkan formatnya?
snakecharmerb