ShutIt:一個基于Python的shell自動化框架
譯者注:本文通過實例簡單介紹了ShutIt這個基于Python的自動化框架的使用方法。除了pexpect,我們又多了這個選擇。以下是譯文。
ShutIt是一個易于使用的基于shell的自動化框架。它對基于python的expect庫(pexpect)進行了包裝。你可以把它看作是“沒有痛點的expect”。它可以通過pip進行安裝。
Hello World
讓我們從最簡單的例子開始吧。創(chuàng)建一個名為example.py的文件:
- import shutit
 - session = shutit.create_session('bash')
 - session.send('echo Hello World', echo=True)
 
運行這個文件:
- python example.py
 
輸出:
- python example.py
 - echo "Hello World"
 - echo "Hello World"
 - Hello World
 - Ians-MacBook-Air.local:ORIGIN_ENV:RhuebR2T#
 
“send”函數(shù)的***個參數(shù)是要運行的命令。“echo”的參數(shù)將會輸出到終端上。默認情況下,ShutIt是靜默的。
登錄服務器
如果你要登陸一臺服務器并執(zhí)行服務器上的命令。可以將example.py改為:
- import shutit
 - session = shutit.create_session('bash')
 - session.login('ssh you@example.com', user='you', password='mypassword')
 - session.send('hostname', echo=True)
 - session.logout()
 
程序?qū)⒌卿浀竭@臺服務器上,并輸出主機名。
- hostname
 - hostname
 - example.com
 - example.com:cgoIsdVv:heDa77HB#
 
顯然,這很不安全!你可以這樣運行:
- 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()
 
它會讓你輸入密碼:
- Input Secret:
 - hostname
 - hostname
 - example.com
 - example.com:cgoIsdVv:heDa77HB#
 
同樣的,“login”方法在登錄后改變了提示符。你給了ShutIt一個登錄命令,并附帶用戶名和密碼(如果需要的話),然后,ShutIt會完成剩余的事情。
“logout”負責終止“login”,并向屏幕輸出發(fā)生的任何變化。
登錄到多臺服務器
假設你有一個集群包含兩臺服務器,并希望同時登錄到這兩個服務器上去。則只需要創(chuàng)建兩個會話,并運行類似的login和send命令:
- 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()
 
將輸出這樣的結(jié)果:
- $ 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#
 
實例:監(jiān)控多臺服務器
我們可以通過添加一些代碼邏輯來檢查命令的輸出,從而將上述代碼變成一個簡單的監(jiān)控工具:
- 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命令的輸出。
還有很多更加優(yōu)雅的方法可以完成上面的操作,但這取決于你想要Python有多聰明。
更復雜的IO – Expecting
假設你需要跟一個命令行程序進行交互,并且要實現(xiàn)自動化操作。在這里,我們使用telnet來舉一個簡單的例子:
- 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”的參數(shù)。你只需要給出telnet提示符的一個子集來進行匹配。
注意“check_exit”的參數(shù),后面我們會講到這個參數(shù)的。上面這段代碼將輸出:
- $ 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.
 
現(xiàn)在回到“checkexit = false”上來。由于telnet命令會返回一個錯誤的退出碼(1),我們不想讓腳本執(zhí)行失敗,這里的“checkexit = false”能讓ShutIt知道你并不關注這個退出碼。
如果你沒有傳入這個參數(shù),ShutIt會給你一個交互式的提示,如果你有終端接入的話。這被稱為“暫停點”。
暫停點
你可以隨便在什么時候通過調(diào)用以下方法來設置一個“暫停點”。
- [...]
 - session.pause_point('This is a pause point')
 - [...]
 
當腳本運行到暫停點時,同時按下“Ctrl”和“]”,則可以讓腳本繼續(xù)執(zhí)行。這對于調(diào)試非常有用:添加一個暫停點,看看周圍,然后繼續(xù)。試試這個:
- 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)
 
程序輸出:
- $ 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
回到我們上面的“監(jiān)控多臺服務器”的例子上來。想象一下,我們要在每臺服務器上運行一個長時間運行的任務。默認情況下,ShutIt會持續(xù)運行很長時間。但是我們可以在后臺運行任務來加快ShutIt的運行速度。
在這里,你可以使用簡單的命令“sleep 60”來嘗試一個例子。
- 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秒,而腳本在一分鐘以后才運行結(jié)束(使用了’wait’方法)。
雖然這個例子看起來是微不足道的,但是想像一下,如果你有數(shù)百臺這樣的服務器需要管理,那么你可以看到這幾行代碼和一個python import所帶來的強大的力量。
更多信息
ShutIt可以做很多事。更多信息,請參閱:
- ShutIt (https://ianmiell.github.io/shutit/)
 - GitHub (https://github.com/ianmiell/shutit/blob/master/README.md)
 















 
 
 















 
 
 
 