標籤:添加 下載檔案 模組 remote 連接埠 get utf-8 bsp 指定
python遠程批量執行
我並不是一個專業的開發,我一直在學習linux營運,對於python也是接觸不久,所以代碼寫的並不是很規範簡潔。
前段時間一個同學找我一起做一個自動化營運平台,我對python的django還沒有瞭解,並且對於HTML和JS這類開發學習還沒有涉及,所以我說我做些背景實現,前端就交給我的同學做。不扯淡了,下面說下我做批量執行的思路。
- 用到的模組:paramiko
- 功能:很簡單就是批量執行命令,類似於ansible,本來想用Fabric,但是想一想還是用paramiko,因為我在學習ansible,ansible裡面就有paramiko。後期還要將設定檔裡面的主機群組放到資料庫裡面。這裡我想使用的mongodb,因為我的主機設定檔寫的是字典的形式,儲存在文檔資料庫中更為方便些。
- 設定檔格式:這裡為了方便擷取資訊,直接寫成了字典的形式,本來前期想用pickle模組進行序列化輸入到檔案中,但是後來發現如果主機要是多的話,手動輸入還是太麻煩了。
- 類:為了後期更好的添加功能,我直接將paramiko的SSHClient寫成了類。後面要添加上傳文本,下載等功能,這就用到了SFTP的功能。
- 函數:這裡面的函數就是對檔案進行條件輸出,找到符合的主機群組名稱。
- 講解下paramiko:paramiko模組在我理解就是依賴ssh遠端一個模組。
(1)、paramiko安裝方式:使用pip安裝即可。
(2)、paramiko核心組件-----SSHClient
SSHClient使用ssh的通道實現和主機的串連和命令執行。
SSHClient中的方法 |
參數和參數說明 |
connect(實現ssh串連和校正) |
hostname:目標主機地址 port:主機連接埠 username:校正的使用者名稱 password:登入密碼 pkey:私密金鑰方式身分識別驗證 key_filename:用於私密金鑰身分識別驗證的檔案名稱 timeout:連線逾時設定 allow_agent:這是布爾型,設定False的時候禁止使用ssh代理 look_for_keys:也是布爾型,禁止在.ssh下面找私密金鑰檔案 compress:設定壓縮 |
exec_command(遠程執行命令) |
stdin,stdout,stderr:這三個分別是標準輸入、輸出、錯誤,用來擷取命令執行結果,並不算方法的參數 command:執行命令的字串,帶雙引號。 bufsize:檔案緩衝大小,預設為1 |
load_system_host_keys(載入本地的公開金鑰檔案) |
filename:指定遠程主機的公開金鑰記錄檔案 |
set_missing_host_key_policy(遠程主機沒有密鑰) |
AutoAddPolicy:自動添加主機名稱和主機密鑰到本地的HostKeys對象 RejectPolicy:自動拒絕未知的主機名稱和密鑰(預設) WarningPolicy:接受未知主機,但是會有警告 |
(3)paramiko的核心組件SFTPClient類
實現遠程檔案的操作,比如上傳、下載、許可權、狀態等。
SFTPClient類的方法 |
參數和參數說明 |
from_transport(使用一個已經通過已經連通的SFTP用戶端通道) |
t:使用的是已經驗證過的傳輸對象 |
put(上傳本地檔案到SFTP伺服器) |
localpath:本地檔案的路徑 remotepath:遠程路徑 callback:擷取已接收的位元組數和總傳輸的位元組數 confirm:檔案上傳完畢後是否調用stat()方法,確定檔案大小 |
get(從SFTP伺服器上下載檔案到本地) |
remotepath:需下載的檔案路徑 localpath:儲存本地的檔案路徑 callback:和put的一樣。 |
mkdir:簡曆目錄 remove:刪除 rename:重新命名 stat:擷取遠程檔案資訊 listdir:擷取指定目錄列表 |
|
(4)、還有個invoke_shell的用法經常使用
invoke_shell(*args, **kwds)Request an interactive shell session on this channel. If the server allows it, the channel will then be directly connected to the stdin, stdout, and stderr of the shell.Normally you would call get_pty before this, in which case the shell will operate through the pty, and the channel will be connected to the stdin and stdout of the pty.When the shell exits, the channel will be closed and can’t be reused. You must open a new channel if you wish to open another shell.
在這個通道請求一個互動shell會話,如果服務允許,這個通道將會直接連接標準輸入、標準輸入和錯誤的shell,通常我們會在使用它之前調用get_pty的用法,這樣shell會話是通過偽終端處理的,並且會話串連標準輸入和輸出,當我們shell退出的時候,這個通道也會關閉,並且能再次使用,你必修重新開另一個shell。
(4)實踐Bastion Host(摘自劉天斯老師的《python自動化營運》)
#定義伺服器資訊hostname = "192.168.0.158"username = "root"password = "aixocm"#定義登入日誌和密碼提示符port = 22passinfo = ‘\‘s password:‘paramiko.util.log_to_file(‘syslogin.log‘)#登入Bastion Host,自動添加hostkeys資訊到主機ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(hostname=blip,username=bluser,password=blpasswd)#建立會話channel = ssh.invoke_shell()channel.settimeout(100)#通道執行shell的ssh串連buff = ‘‘resp = ‘‘channel.send(‘ssh ‘+username+‘@‘+hostname+‘\n‘)while not buff.endswith(passinfo): try: resp = channel.recv(9999) except Exception,e: print ‘Error info:%s connection time.‘ % (str(e)) channel.close() ssh.close() sys.exit() buff += resp if not buff.find(‘yes/no‘) == -1: channel.send(‘yes\n‘) buff = ‘‘channel.send(password+‘\n‘)buff = ‘‘while not buff.endswith(‘# ‘): resp = channel.recv(9999) if not resp.find(passinfo) == -1: print ‘Error info:Authentication failed.‘ channel.close() ssh.close()
View Code
- 設定檔:代碼:
{"hostname":"web","host_ip":["192.168.0.157","192.168.0.158","192.168.0.159"]}
類:#!/usr/bin/env pyth#coding:utf-8import paramiko
class action(object): def __init__(self, IP, username, command): self.IP = IP self.username = username self.command = command def ssh_connect(self): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())try: ssh.connect(hostname=self.IP, username=self.username) stdin,stdout,stderr=ssh.exec_command(self.command) print "######################> %s <####################" %(self.IP) print stderr.read() print stdout.read() ssh.close()
except Exception,e: print "######################> %s <####################" %(self.IP) print
執行主函數:
from simple1 import action
def get_values(hostname): conf_file=open(‘scn.conf‘,‘r‘) lines = conf_file.readlines() for line in lines: line = line.strip("\n") line = eval(line) if hostname == line["hostname"]: return(line) break conf_file.close()if __name__ == "__main__": hostname = raw_input("write your hostname:") username = raw_input("write your username:") command = raw_input("write your excute command:") host = get_values(hostname) host_ip = list(host["host_ip"]) for i in range(0,len(host_ip)): conn = action(host_ip[i],username,command) conn.ssh_connect()
注意這裡面我沒有添加password和port,port預設使用的ssh的22號連接埠,password我直接使用ssh-keygen和ssh-copy-id進行無密碼登入。
python之實現批量遠程執行命令(Bastion Host)