譯者注:本文通過例項簡單介紹了ShutIt這個基於Python的自動化框架的使用方法。除了pexpect,我們又多了這個選擇。以下是譯文。
ShutIt是一個易於使用的基於shell的自動化框架。它對基於python的expect庫(pexpect)進行了包裝。你可以把它看作是“沒有痛點的expect”。它可以通過pip進行安裝。
Hello World
讓我們從最簡單的例子開始吧。建立一個名為example.py的檔案:
1 2 3 |
import shutit session = shutit.create_session('bash') session.send('echo Hello World', echo=True) |
執行這個檔案:
1 |
python example.py |
輸出:
1 2 3 4 5 |
python example.py echo "Hello World" echo "Hello World" Hello World Ians-MacBook-Air.local:ORIGIN_ENV:RhuebR2T# |
“send”函式的第一個引數是要執行的命令。“echo”的引數將會輸出到終端上。預設情況下,ShutIt是靜默的。
登入伺服器
如果你要登陸一臺伺服器並執行伺服器上的命令。可以將example.py改為:
1 2 3 4 5 |
import shutit session = shutit.create_session('bash') session.login('ssh you@example.com', user='you', password='mypassword') session.send('hostname', echo=True) session.logout() |
程式將登入到這臺伺服器上,並輸出主機名。
1 2 3 4 |
hostname hostname example.com example.com:cgoIsdVv:heDa77HB# |
顯然,這很不安全!你可以這樣執行:
1 2 3 4 5 6 |
import shutit session = shutit.create_session('bash') password = session.get_input('', ispass=True) session.login('ssh you@example.com', user='you', password=password) session.send('hostname', echo=True) session.logout() |
它會讓你輸入密碼:
1 2 3 4 5 |
Input Secret: hostname hostname example.com example.com:cgoIsdVv:heDa77HB# |
同樣的,“login”方法在登入後改變了提示符。你給了ShutIt一個登入命令,並附帶使用者名稱和密碼(如果需要的話),然後,ShutIt會完成剩餘的事情。
“logout”負責終止“login”,並向螢幕輸出發生的任何變化。
登入到多臺伺服器
假設你有一個叢集包含兩臺伺服器,並希望同時登入到這兩個伺服器上去。則只需要建立兩個會話,並執行類似的login和send命令:
1 2 3 4 5 6 7 8 9 10 11 |
import shutit session1 = shutit.create_session('bash') session2 = shutit.create_session('bash') password1 = session1.get_input('Password for server1', ispass=True) password2 = session2.get_input('Password for server2', ispass=True) session1.login('ssh you@one.example.com', user='you', password=password1) session2.login('ssh you@two.example.com', user='you', password=password2) session1.send('hostname', echo=True) session2.send('hostname', echo=True) session1.logout() session2.logout() |
將輸出這樣的結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ python example.py Password for server1 Input Secret: Password for server2 Input Secret: hostname hostname one.example.com one.example.com:Fnh2pyFj:qkrsmUNs# hostname hostname two.example.com two.example.com:Gl2lldEo:D3FavQjA# |
例項:監控多臺伺服器
我們可以通過新增一些程式碼邏輯來檢查命令的輸出,從而將上述程式碼變成一個簡單的監控工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import shutit capacity_command="""df / | awk '{print $5}' | tail -1 | sed s/[^0-9]//""" session1 = shutit.create_session('bash') session2 = shutit.create_session('bash') password1 = session.get_input('Password for server1', ispass=True) password2 = session.get_input('Password for server2', ispass=True) session1.login('ssh you@one.example.com', user='you', password=password1) session2.login('ssh you@two.example.com', user='you', password=password2) capacity = session1.send_and_get_output(capacity_command) if int(capacity) < 10: print('RUNNING OUT OF SPACE ON server1!') capacity = session2.send_and_get_output(capacity_command) if int(capacity) < 10: print('RUNNING OUT OF SPACE ON server2!') session1.logout() session2.logout() |
在這裡,我們用了“sendandget_output”方法來獲取capacity_command命令的輸出。
還有很多更加優雅的方法可以完成上面的操作,但這取決於你想要Python有多聰明。
更復雜的IO – Expecting
假設你需要跟一個命令列程式進行互動,並且要實現自動化操作。在這裡,我們使用telnet來舉一個簡單的例子:
1 2 3 4 5 6 |
import shutit session = shutit.create_session('bash') session.send('telnet', expect='elnet>', echo=True) session.send('open google.com 80', expect='scape character', echo=True) session.send('GET /', echo=True, check_exit=False) session.logout() |
注意“expect”的引數。你只需要給出telnet提示符的一個子集來進行匹配。
注意“check_exit”的引數,後面我們會講到這個引數的。上面這段程式碼將輸出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ python example.py telnet telnet> open google.com 80 Trying 216.58.214.14... Connected to google.com. Escape character is '^]'. GET / HTTP/1.0 302 Found Cache-Control: private Content-Type: text/html; charset=UTF-8 Referrer-Policy: no-referrer Location: http://www.google.co.uk/?gfe_rd=cr&ei=huczWcj3GfTW8gfq0paQDA Content-Length: 261 Date: Sun, 04 Jun 2017 10:57:10 GMT <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>302 Moved</TITLE></HEAD><BODY> <H1>302 Moved</H1> The document has moved <A HREF="http://www.google.co.uk/?gfe_rd=cr&ei=huczWcj3GfTW8gfq0paQDA"> here </A>. </BODY></HTML> Connection closed by foreign host. |
現在回到“checkexit = false”上來。由於telnet命令會返回一個錯誤的退出碼(1),我們不想讓指令碼執行失敗,這裡的“checkexit = false”能讓ShutIt知道你並不關注這個退出碼。
如果你沒有傳入這個引數,ShutIt會給你一個互動式的提示,如果你有終端接入的話。這被稱為“暫停點”。
暫停點
你可以隨便在什麼時候通過呼叫以下方法來設定一個“暫停點”。
1 2 3 |
[...] session.pause_point('This is a pause point') [...] |
當指令碼執行到暫停點時,同時按下“Ctrl”和“]”,則可以讓指令碼繼續執行。這對於除錯非常有用:新增一個暫停點,看看周圍,然後繼續。試試這個:
1 2 3 4 |
import shutit session = shutit.create_session('bash') session.pause_point('Have a look around!') session.send('echo "Did you enjoy your pause point?"', echo=True) |
程式輸出:
1 2 3 4 5 6 7 8 9 10 11 |
$ python example.py Have a look around! Ians-Air.home:ORIGIN_ENV:I00LA1Mq# bash imiell@Ians-Air:/space/git/shutit ⑂ master + CTRL-] caught, continuing with run... 2017-06-05 15:12:33,577 INFO: Sending: exit 2017-06-05 15:12:33,633 INFO: Output (squashed): exitexitIans-Air.home:ORIGIN_ENV:I00LA1Mq# [...] echo "Did you enjoy your pause point?" echo "Did you enjoy your pause point?" Did you enjoy your pause point? Ians-Air.home:ORIGIN_ENV:I00LA1Mq# |
更復雜的IO – Backgrounding
回到我們上面的“監控多臺伺服器”的例子上來。想象一下,我們要在每臺伺服器上執行一個長時間執行的任務。預設情況下,ShutIt會持續執行很長時間。但是我們可以在後臺執行任務來加快ShutIt的執行速度。
在這裡,你可以使用簡單的命令“sleep 60”來嘗試一個例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import shutit import time long_command="""sleep 60""" session1 = shutit.create_session('bash') session2 = shutit.create_session('bash') password1 = session1.get_input('Password for server1', ispass=True) password2 = session2.get_input('Password for server2', ispass=True) session1.login('ssh you@one.example.com', user='you', password=password1) session2.login('ssh you@two.example.com', user='you', password=password2) start = time.time() session1.send(long_command, background=True) session2.send(long_command, background=True) print('That took: ' + str(time.time() - start) + ' seconds to fire') session1.wait() session2.wait() print('That took: ' + str(time.time() - start) + ' seconds to complete') |
我的膝上型電腦說,執行這兩個命令只需花費0.5秒,而指令碼在一分鐘以後才執行結束(使用了’wait’方法)。
雖然這個例子看起來是微不足道的,但是想像一下,如果你有數百臺這樣的伺服器需要管理,那麼你可以看到這幾行程式碼和一個python import所帶來的強大的力量。
更多資訊