Python利用多線程實現ssh併發訪問

7.1 問題
編寫一個remote_comm.py腳本,實現以下功能:

在文件中取出所有遠程主機IP地址
在shell命令行中接受遠程服務器IP地址文件、遠程服務器密碼以及在遠程主機上執行的命令
通過多線程實現在所有的遠程服務器上併發執行命令
7.2 步驟
實現此案例需要按照如下步驟進行。

步驟一:安裝paramiko

paramiko 遵循SSH2協議,支持以加密和認證的方式,進行遠程服務器的連接,可以實現遠程文件的上傳,下載或通過ssh遠程執行命令。

[root@localhost ~]# pip3 install paramiko
...
...
Successfully installed bcrypt-3.1.4 paramiko-2.4.1 pyasn1-0.4.4 pynacl-1.2.1
You are using pip version 9.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
測試是否安裝成功

>>> import paramiko
>>>

步驟二:編寫腳本

[root@localhost day11]# vim remote_comm.py
#!/usr/bin/env python3
import sys
import getpass
import paramiko
import threading
import os
#創建函數實現遠程連接主機、服務器密碼以及在遠程主機上執行的命令的功能
def remote_comm(host, pwd, command):
#創建用於連接ssh服務器的實例
    ssh = paramiko.SSHClient()
#設置自動添加主機密鑰
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#連接ssh服務器,添加連接的主機、用戶名、密碼填好
    ssh.connect(hostname=host, username='root', password=pwd)
#在ssh服務器上執行指定命令,返回3項類文件對象,分別是,輸入、輸出、錯誤
    stdin, stdout, stderr = ssh.exec_command(command)
#讀取輸出
    out = stdout.read()
#讀取錯誤
    error = stderr.read()
#如果有輸出
    if out:
#打印主機輸出內容
        print('[%s] OUT:\n%s' % (host, out.decode('utf8')))
#如果有錯誤
    if error:
#打印主機錯誤信息
        print('[%s] ERROR:\n%s' % (host, error.decode('utf8')))
#程序結束
    ssh.close()
if __name__ == '__main__':
#設定sys.argv長度,確保remote_comm函數中參數數量
    if len(sys.argv) != 3:
        print('Usage: %s ipaddr_file "command"' % sys.argv[0])
        exit(1)
#判斷命令行上輸入如果不是文件,確保輸入的是文件  
    if not os.path.isfile(sys.argv[1]):
        print('No such file:', sys.argv[1])
        exit(2)
#fname爲存儲遠程主機ip的文件,用sys.argv方法,可以在執行腳本時再輸入文件名,更爲靈活
    fname = sys.argv[1]
#command爲在遠程主機上執行的命令,用sys.argv方法,可以在執行腳本時再輸入相應命令,command爲remote_comm函數第三個參數
    command = sys.argv[2]
#通過getpass輸入遠程服務器密碼,pwd爲remote_comm函數第二個參數
    pwd = getpass.getpass()
#打開存有遠程主機ip的文件
    with open(fname) as fobj:
#將遍歷文件將ip以列表形式存入ips,line.strip()可以去掉每行ip後\n
        ips = [line.strip() for line in fobj]
#循環遍歷列表,獲取ip地址,ip爲remote_comm函數第一個參數
    for ip in ips:
#將讀取到的ip地址作爲remote_comm函數實際參數傳遞給函數,ips中有幾個ip地址循環幾次
#創建多線程
        t = threading.Thread(target=remote_comm, args=(ip, pwd, command))
#啓用多線程
        t.start()

步驟三:測試腳本執行

#參數給少了效果如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt
Usage: remote_comm.py ipaddr_file “command”
#參數給多了效果如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt id zhangsan
Usage: remote_comm.py ipaddr_file “command”
#正常顯示如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt “id zhangsan”
Password:
[192.168.4.2] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 組=1001(zhangsan)
[192.168.4.3] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 組=1001(zhangsan)
[root@localhost day11]# python3 remote_comm.py server_addr.txt “echo redhat | passwd –stdin root”
Password:
[192.168.4.3] OUT:
更改用戶root的密碼:
passwd:所有的身份驗證令牌已經成功更新。
[192.168.4.2] OUT:
更改用戶root的密碼:
passwd:所有的身份驗證令牌已經成功更新。
#此時密碼已經變成redhat
[root@localhost day11]# python3 remote_comm.py server_addr.txt “id zhangsan”
Password:
[192.168.4.2] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 組=1001(zhangsan)
[192.168.4.3] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 組=1001(zhangsan)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章