天天看點

ssh批量登入并執行指令(python實作)

來自 www.cnblogs.com/ma6174/archive/2012/05/25/2508378.html  

    區域網路内有一百多台電腦,全部都是linux作業系統,所有電腦組態相同,系統完全相同(包括使用者名和密碼),ip位址是自動配置設定的。現在有個任務是在這些電腦上執行某些指令,者說進行某些操作,比如安裝某些軟體,拷貝某些檔案,批量關機等。如果一台一台得手工去操作,費時又費力,如果要進行多個操作就更麻煩啦。

      或許你會想到網絡同傳, 網絡同傳是什麼?就是在一台電腦上把電腦裝好,配置好,然後利用某些軟體,如“聯想網絡同傳”把系統原樣拷貝過去,在裝系統時很有用,隻要在一台電腦上裝好,同傳以後所有的電腦都裝好作業系統了,很友善。同傳要求所有電腦硬體完全相同,在聯想的電腦上裝的系統傳到方正電腦上肯定會出問題的。傳系統也是很費時間的,根據硬碟大小,如果30G硬碟,100多台電腦大約要傳2個多小時,反正比一台一台地安裝快!但是如果系統都傳完了,發現忘了裝一個軟體,或者還需要做些小修改,再同傳一次可以,但是太慢,傳兩次半天時間就沒了。這時候我們可以利用ssh去控制每台電腦去執行某些指令。

      先讓我們回憶一下ssh遠端登入的過程:首先執行指令 ssh [email protected] ,第一次登入的時候系統會提示我們是否要繼續連接配接,我們要輸入“yes”,然後等一段時間後系統提示我們輸入密碼,正确地輸入密碼之後我們就能登入到遠端計算機,然後我們就能執行指令了。我們注意到這裡面有兩次人機互動,一次是輸入‘yes’,另一次是輸入密碼。就是因為有兩次互動我們不能簡單的用某些指令去完成我們的任務。我們可以考慮把人機互動變成自動互動,python的pexpect子產品可以幫我們實作自動互動。下面這段代碼是用pexpect實作自動互動登入并執行指令的函數:

# !/usr/bin/env python

#  -*- coding: utf-8 -*-

import pexpect

def ssh_cmd(ip, passwd, cmd):

    ret = -1

    ssh = pexpect.spawn( ' ssh root@%s "%s" ' % (ip, cmd))

     try:

        i = ssh.expect([ ' password: ',  ' continue connecting (yes/no)? '], timeout=5)

         if i == 0 :

            ssh.sendline(passwd)

         elif i == 1:

            ssh.sendline( ' yes\n ')

            ssh.expect( ' password:  ')

            ssh.sendline(passwd)

        ssh.sendline(cmd)

        r = ssh.read()

         print r

        ret = 0

     except pexpect.EOF:

         print  " EOF "

        ssh.close()

        ret = -1

     except pexpect.TIMEOUT:

         print  " TIMEOUT "

        ssh.close()

        ret = -2

    return ret 

      利用pexpect子產品我們可以做很多事情,由于他提供了自動互動功能,是以我們可以實作ftp,telnet,ssh,scp等的自動登入,還是比較實用的。根據上面的代碼相信讀者已經知道怎麼實作了(python就是那麼簡單!)。

      用上面的代碼去完成任務還是比較費時間的,因為程式要等待自動互動出現,另外ubuntu用ssh連接配接就是比較慢,要進行一系列的驗證,這樣才展現出ssh的安全。我們要提高效率,在最短的時間内完成。後來我發現了python裡面的paramiko子產品,用這個實作ssh登入更加簡單。看下面的代碼:

# -*- coding: utf-8 -*-

# !/usr/bin/python 

import paramiko

import threading

def ssh2(ip,username,passwd,cmd):

     try:

        ssh = paramiko.SSHClient()

        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        ssh.connect(ip,22,username,passwd,timeout=5)

         for m  in cmd:

            stdin, stdout, stderr = ssh.exec_command(m)

#            stdin.write("Y")   #簡單互動,輸入 ‘Y’ 

            out = stdout.readlines()

             # 螢幕輸出

             for o  in out:

                 print o,

         print  ' %s\tOK\n '%(ip)

        ssh.close()

     except :

         print  ' %s\tError\n '%(ip)

if  __name__== ' __main__ ':

    cmd = [ ' cal ', ' echo hello! '] # 你要執行的指令清單

    username =  ""   # 使用者名

    passwd =  ""     # 密碼

    threads = []    # 多線程

     print  " Begin...... "

     for i  in range(1,254):

        ip =  ' 192.168.1. '+str(i)

        a=threading.Thread(target=ssh2,args=(ip,username,passwd,cmd))

        a.start() 

上面的程式還是有些技巧的:

1.利用多線程,同時發出登入請求,同時去連接配接電腦,這樣速度快很多,我試了一下,如果不用多線程,直接一個一個挨着執行的話,大約5~10秒鐘才能對一台電腦操作完,具體時間要根據指令的來決定,如果是軟體安裝或者解除安裝時間要更長一些。這樣下來怎麼也要一二十分鐘,用多線程後就快多了,所有的指令執行完用了不到2分鐘!

2.最好用root使用者登入,因為安裝或者解除安裝軟體的時候如果用普通使用者又會提示輸入密碼,這樣又多了一次互動,處理起來就比較麻煩!安裝軟體時apt-get install xxx 最好加上“-y”參數,因為有時安裝或删除軟體時提示是否繼續安裝或解除安裝,這又是一次自動互動!加上那個參數後就沒有人機互動了。

3. 循環時循環所有ip,因為計算機的ip是路由器自動配置設定的,保險起見,最好全部都執行,保證沒有遺漏的主機

4.遠端執行指令時如果有互動,可以這樣用 stdin.write("Y")來完成互動,“Y”就是輸入“Y”。

5.把所有的指令放到一個清單裡面,周遊清單可以依次執行清單裡面的指令

6.為了更好的進行控制,最好在電腦上提前把root使用者打開,裝好ssh伺服器并讓其開機自動執行。