引言
對于簡單網絡管理協議 (SNMP),大多數系統管理員都具有一定的使用經驗,或者至少聽說過它。如果您正在一個數據中心工作,那么您每天都可能采用某種方式與 SNMP 進行交互。有許多給人印象深刻的、同等規模的網絡管理系統 (NMS) 或者網絡監視系統使用了 SNMP 監視,但本文并不打算介紹這些系統。本文主要涉及的是通過 Python? 語言來研究 SNMP,并親自編寫相關的代碼。
一位朋友最近告訴我,有時候遇到的情況就像:只是希望沿著街道一路走到奶奶家,而不需要乘坐像 Saturn V 火箭一樣飛快。有許多任務,如果利用或者配置大規模的 NMS,就好像是一個 Saturn V 火箭,在填滿液氧罐之前,先嘗試一下使用 Python,那么您將得到更好的服務。了解如何編寫靈活的 Python 代碼與 SNMP 進行交互,這可能是系統管理員可以獲得的、最有趣且最高效的技能之一。盡管 SNMP 的設置和使用非常復雜,但本文中所討論的內容將使它變得非常有趣。
安裝和配置 Net-SNMP
要學習本文中的內容,您需要在您的 *nix 計算機中安裝最新的 Python(即 Python 2.3 或者更高版本)。在撰寫本文時,Python 2.5.1 是 Python 的最新版本。您還需要 IPython,以便以交互的方式使用帶 Python 綁定的 Net-SNMP 庫。Net-SNMP 團隊對各種操作系統中的支持進行了詳細測試,具體包括 AIX?、HP-UX?、GNU/Linux? 分發版(如 Red Hat)、Windows?,甚至 OS X?。
安裝 IPython 是一項非常簡單的工作。一個很好的選擇是使用 Easy Install 來管理 Python 包。通過運行 ez_setup.py 腳本,您可以很容易地安裝任何 Python 包。例如,您只需要鍵入以下命令:
1
|
easy_install ipython |
其他可選的安裝方式包括,使用您最喜歡的包管理系統、或者只需下載 IPython 并鍵入以下命令:
1
|
python setup.py install |
請注意,干線 (trunk) 指的是版本控制系統中的根路徑,其中保存了最近的代碼副本。此外,干線還常常表示一個子版本和版本控制系統。有關更詳細的內容,請參見參考資料部分中的子版本鏈接。
要學習本文中的內容,您需要確保您的客戶端計算機、或者運行所有代碼的計算機都安裝了 NET-SNMP Version 5.4.x 或者更高版本,因為從這個源代碼版本開始,包括了 Python 綁定。在大多數情況下,綁定的安裝需要對源文件進行編譯;然而,也可以使用 Red Hat Package Managers (RPM)。如果你有興趣和時間,那么可以從 Net-SNMP Web 站點查看一下它的最新版本。
有許多編譯選項可供使用,但主要的任務是對 NET-SNMP 進行正確編譯,然后運行 Python 目錄中的、獨立的 Python 安裝程序。另一個需要注意的問題是,當您進行編譯并運行 ./configure 的時候,它將運行本地計算機(正在編譯代理的計算機)的配置腳本。您不應該使用該配置腳本,對于本文而言,您只需要創建一個簡單的配置腳本。
對 /etc/snmp/snmpd.conf 中所存儲的配置文件進行備份,并構建下面這個非常基本的配置:
1
2
3
|
syslocation "My Local Machine" syscontact me@localhost.com rocommunity public |
保存它,并重新啟動 snmpd 守護進程。在大多數 *nix 系統中,可以使用 /etc/init.d/snmpd restart 來完成這項工作。
除非在不得已的情況下,否則最好不要對處于活動開發階段的版本進行編譯,因為這樣做,您將需要自己動手修復有問題的代碼。在 CentOS 5 或者 Red Hat Enterprise Linux 5 (RHEL 5) 中,您可以下載最新的、穩定的源文件 RPM(在撰寫本文之時,是 5.4.1 版本)。請注意,您還需要使用 Python 源文件來構建綁定。因此,如果您正在使用一臺基于 Red Hat 的計算機,那么請確保為特定的 *nix 操作系統安裝了 python-dev(或者其等價物)和 Python Header 文件。如果您在從源文件構建 RPM 的過程中,需要任何幫助的話,請參考官方的 Red Hat 文檔。從源文件構建包可能是一個非常復雜的主題,并且已經超出了本文的范圍。如果您在使用 Python 綁定的時候遇到了麻煩,那么您應該在 Net-SNMP 郵件列表中請求幫助。
對代碼進行分析
還等什么呢?假設您已經安裝了 Python 綁定和 IPython。現在,您已經做好了使用 IPython 的準備,并開始相關的工作。盡管在某些時候,您可能還需要瀏覽 IPython 文檔。Jeff Rush 是當前的 Python Advocacy Coordinator,他為 IPython 提供了一些非常好的屏幕錄像內容。好的,讓我們開始進行編碼。
讓我們進行一次簡單的查詢,以便通過使用計算機的對象標識符 (OID) 值 sysDescr 來標識一臺計算機。通過鍵入 ipython 啟動 IPython,然后執行這個交互式會話:
清單 1. IPython 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
In [ 1 ]: import netsnmp In [ 2 ]: oid = netsnmp.Varbind( 'sysDescr' ) In [ 3 ]: result = netsnmp.snmpwalk(oid, ...: Version = 2 , ...: DestHost = "localhost" , ...: Community = "public" ) In [ 4 ]: result = netsnmp.snmpwalk(oid, Version = 2 , DestHost = "localhost" , Community = "public" ) In [ 16 ]: result Out[ 16 ]: ('Linux localhost 2.6 . 18 - 8.1 . 14.el5 #1 SMP Thu Sep 27 18 : 58 : 54 EDT 2007 i686',) |
請注意,您所得到的 result 值與這里所顯示的 result 值是不同的。如果您已經遵循了上面清單 1 中所顯示的配置,那么所有其他的內容都應該是可用的。如果您對 SNMP 比較熟悉,那么您可能馬上就能夠明白這些內容的實際作用。
使用 IPython 來測試 SNMP 代碼片段的好處之一是,它就好像是一個普通的 Shell,并且許多基本的、交互式 Shell 的概念“都可以起作用”,但需要說明的是,它們是以 python 方式進行工作的。編寫 SNMP 代碼可能是一項非常單調乏味的活動,但是通過 IPython 來使用 Net-SNMP 庫將使其變得非常有趣。
正如您所看到的,要將結果轉換為 Python 數據類型,這項任務是非常簡單的。這就是為什么 IPython 和 Net-SNMP 可以很好地在一起工作的原因。現在,對于編寫自定義腳本來說,只需要以交互方式分析 OID 的組合以進行查詢。在理想的情況下,需要運行一個大規模的、易于配置的 NMS 設置腳本,自動地將新的計算機集成到網絡中。
當然,并不存在這種理想的情況,您需要了解如何將一些好的 SNMP 代碼組合到一起,對于一名系統管理員來說,這是非常有用的。下面給出一個示例情況,假設您剛剛將一個高速 DDR 轉換為正在運行 Ubuntu Linux 的 2 TB RAID 0 服務器,因為您必須在一個小時的時間內解決問題,所以您不得不這樣做。
現在,您遇到了很大的麻煩,并且您只有幾分鐘的時間來監視具體的問題,以了解是否需要開始發送簡歷、或者是否應該開始準備講話并請求升職。讓我們使用 IPython 中的編輯功能來編寫腳本,并將它保存到文件中,然后在不離開 IPython 的情況下,在一個會話中運行它: ed snmpinput.py
清單 2. IPython 模塊的創建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import netsnmp class snmpSessionBaseClass( object ): """A Base Class For a SNMP Session""" def __init__( self , oid = "sysDescr" , Version = 2 , DestHost = "localhost" , Community = "public" ): self .oid = oid self .Version = Version self .DestHost = DestHost self .Community = Community def query( self ): """Creates SNMP query session""" try : result = netsnmp.snmpwalk( self .oid, Version = self .Version, DestHost = self .DestHost, Community = self .Community) except : import sys print sys.exc_info() result = None return result |
對 IPython 進行自定義以使用正確的編輯器
通過編輯 $HOME/.ipython/ipythonrc,您可以對 Ipython 進行自定義。首先需要進行自定義的內容之一是 %edit 命令,可以通過鍵入 ed 來調用該命令。在缺省情況下,它被設置為使用 vi,但是您可以更改它,以便使用其他編輯器,包括 Emacs。關于如何更改您的環境,本文給出了相應的指導。您還可以使用下面的命令來啟動 Ipython,以便以硬編碼的形式指定使用某個特定的編輯器: ipython -editor=vim。
繼續執行,將下面的代碼剪切并粘貼到您剛剛創建的文件中。當保存這個文件時,IPython 將自動地運行它,并將該類放置到您環境中相應的模塊中。如果您鍵入 who,那么您將看到與以下所示類似的內容:
1
2
|
In [ 2 ]: who netsnmp snmpSessionBaseClass |
這項操作的功能非常強大,因為您可以獲得使用您最喜歡的文本編輯器(也許是 Vim 或者 Emacs)的所有優點,然后在交互的 IPython Shell 會話中立即使用這些代碼。請注意,如果您已經編寫了一個模塊,那么您還可以簡單地鍵入并運行它,以獲得相同的結果。執行和運行 IPython 中的模塊,這就相當于運行其中的代碼,并將其放入到 IPython 環境中。
以迭代的方式進行編碼
現在通過使用 IPython,可以將 Python Shell、UNIX Shell 和您最喜歡的文本編輯器的最佳特性組合到一起。在與像 SNMP 庫這樣非常復雜的對象進行交互時,您需要使用可以獲得的所有幫助,而在這個示例中,真正地展示了 IPython 的強大功能。
您可以動態地編寫一些模塊,并且您可以在稍后對其進行測試和使用。IPython 可以與任何編程風格很好地融合在一起,包括測試驅動的開發 (TDD) 或者測試增強的開發 (TED)。為了證明這種便利性,讓我們轉到您剛剛編寫的模塊。
既然已經有一個面向對象的 SNMP 接口,那么您就可以開始向本地計算機進行詢問:
清單 3. IPython 迭代式編碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
In [ 1 ]: run snmpinput In [ 2 ]: who netsnmp snmpSessionBaseClass In [ 3 ]: s = snmpSessionBaseClass() In [ 4 ]: s.query() Out[ 4 ]: ( 'Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686' ,) In [ 5 ]: result = s.query() In [ 6 ]: len (result) Out[ 6 ]: 1 |
通過使用這個模塊獲得相關的結果,這是非常容易的,但是您基本上只是在運行一個硬編碼腳本,因此需要更改 OID 對象的值,以遍歷系統子樹:
清單 4. 更改 OID 對象的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
In [ 7 ]: s.oid Out[ 7 ]: 'sysDescr' In [ 8 ]: s.oid = ".1.3.6.1.2.1.1" In [ 9 ]: result = s.query() In [ 10 ]: print result ( 'Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686' , '.1.3.6.1.4.1.8072.3.2.10' , '121219' , 'me@localhost.com' , 'localhost' , '"My Local Machine" ', ' 0 ', ' . 1.3 . 6.1 . 6.3 . 10.3 . 1.1 ', ' . 1.3 . 6.1 . 6.3 . 11.3 . 1.1 ', '.1.3.6.1.6.3.15.2.1.1' , '.1.3.6.1.6.3.1' , '.1.3.6.1.2.1.49' , '.1.3.6.1.2.1.4' , '.1.3.6.1.2.1.50' , '.1.3.6.1.6.3.16.2.2.1' , 'The SNMP Management Architecture MIB.' , 'The MIB for Message Processing and Dispatching. ', ' The management information definitions for the SNMP User - based Security Model. ', ' The MIB module for SNMPv2 entities ', ' The MIB module for managing TCP implementations ', ' The MIB module for managing IP and ICMP implementations ', ' The MIB module for managing UDP implementations ', ' View - based Access Control Model for SNMP. ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ') |
正如您可以看到的,要使用這個模塊并開始分析整個網絡(一次一臺計算機),這項任務是非常容易的。請仔細地進行分析,并確定需要在網絡中進行查詢的內容。這是 IPython 的另一個有趣的特性,有必要對其進行深入研究。IPython 具有一個令人難以置信的特性,即允許您將 Python 代碼片段作為后臺進程來運行。幸運的是,進行這項操作非常簡單。讓我們再次運行相同的查詢,但這一次將其作為后臺進程運行(請參見清單 5)。
清單 5. IPython 迭代式編碼示例——后臺進程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
In [ 11 ]: bg s.query() Starting job # 0 in a separate thread. In [ 12 ]: jobs[ 0 ].status Out[ 12 ]: 'Completed' In [ 16 ]: jobs[ 0 ].result Out[ 16 ]: ( 'Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686' , '.1.3.6.1.4.1.8072.3.2.10' , '121219' , 'me@localhost.com' , 'localhost' , '"My Local Machine" ', ' 0 ', ' . 1.3 . 6.1 . 6.3 . 10.3 . 1.1 ', ' . 1.3 . 6.1 . 6.3 . 11.3 . 1.1 ', '.1.3.6.1.6.3.15.2.1.1' , '.1.3.6.1.6.3.1' , '.1.3.6.1.2.1.49' , '.1.3.6.1.2.1.4' , '.1.3.6.1.2.1.50' , '.1.3.6.1.6.3.16.2.2.1' , 'The SNMP Management Architecture MIB.' , 'The MIB for Message Processing and Dispatching. ', ' The management information definitions for the SNMP User - based Security Model. ', ' The MIB module for SNMPv2 entities ', ' The MIB module for managing TCP implementations ', ' The MIB module for managing IP and ICMP implementations ', ' The MIB module for managing UDP implementations', 'View-based Access Control Model for SNMP.' , '0' , '0' , '0' , '0' , '0' , '0' , '0' , '0' ) |
令人激動的是,IPython 中的后臺線程是一種非常有價值的功能,但它只能與支持異步線程的庫一起工作。不幸的是,Net-SNMP 是同步的。如果您對這一點感興趣,那么可以通過將 s.oid 值更改為 .iso 來進行測試。在查詢完成之前,您應該可以注意到,IPython 解釋器發生了“阻塞”或者“掛起”。盡管只是一個警告,但對整個 .iso 樹的 SNMP 遍歷可能會花費較長的時間,因此您可能會接受我的觀點。
當然,還有另一種解決方案。您可以使用 Python 所提供的眾多處理庫中的其中一個,為這個阻塞的進程派生新的進程。Python Cheese Shop 提供了一些第三方庫。如果您正在使用 easy_install,那么要安裝一個包(如 Parallel Python)并使用 Net-SNMP 來測試這個庫,將是相當簡單的,因此這將由您來決定。
1
|
easy_install http: //www .parallelpython.com /downloads/pp/pp-1 .5.zip |
這里要展示的最后一個特性是,在 IPython Shell 中運行單元測試。在對模塊進行更改時,需要頻繁地運行單元測試,而這也是非常容易的。您需要添加一個標記以運行 run -e,這樣一來,您就可以在 IPython Shell 中避免回溯到單元測試模塊。您可以在本文所附帶的源文件中下載這個單元測試。
請注意,IPython 0.8.2 還有一個新的文檔測試特性,它允許您在 IPython 中生成文檔測試。文檔測試是 Python 的一個很好的特性,因為與其他特性一起,它提供了一種為 API 創建可測試文檔的方法。下面給出了一個示例,以說明如何在 IPython 中為我們的模塊運行 doctest:
清單 6.以 doctest 模式運行 IPython
1
2
3
4
5
6
7
8
9
10
|
In [ 5 ]: % doctest_mode * * * Pasting of code with ">>>" or "..." has been enabled. Exception reporting mode: Plain Doctest mode is : ON >>> from snmpinput import snmpSessionBaseClass >>> s = snmpSessionBaseClass() >>> s.query() ( 'Linux devmws2.racemi.com 2.6.9-55.0.2.EL #1 Tue Jun 26 14:08:18 EDT 2007 i686' ,) |
因為 doctest 模式將不加分析地執行 Python 語句,所以您必須小心,不要在 doctest 中使用可能更改的值,就像上面所給出的值。如果您在模塊的 docstring 中粘貼了數行代碼,那么您可以通過使用下面的方法來測試您的 API 文檔:
1
2
3
4
5
6
|
def _test(): import doctest doctest.testmod() if __name__ = = "__main__" : _test() |
總結
在本文中,您已經了解了協同使用 Net-SNMP 和 IPython 將成為一種功能強大的組合。本文介紹了下面幾個主要概念:
- Python 綁定:Net-SNMP 現在提供了 Python 綁定,這使得我們能夠充分地利用 Python 的功能來處理 SNMP 協議。
- 處理庫:目前,Python 綁定是同步的,但是使用處理庫可以為每個請求派生新的進程,從而解決這個問題。
- 靈活的技術:對于系統管理員和軟件工程師來說,IPython 是一種非常成熟、并且功能非常強大的工具。盡管本文只是簡要地介紹了幾種靈活的技術,如文檔測試和單元測試,但是您可以應用這些技術,以進行任何以測試為中心的開發、或者以交互的方式編寫和分析代碼。
- SNMP 和 IPython:對于 SNMP 和 IPython 在單獨或者共同使用時能夠實現的功能,本文只是進行了簡要介紹。
SNMP 非常復雜,它幾乎使人們不敢想象編寫任何有意義的代碼,但是,我們希望本文所介紹的技術能夠激發某些新的觀點。如果您很好奇,想知道 SNMP 的 Python 實現究竟到了什么程度,那么可以研究一下 Zenoss,下載一個虛擬機,并對它進行測試。還有一個 API,您可以利用它來編寫腳本,因此您可以將這里所學到的內容和全面的 Python NMS 相結合。當然,也適用于任何其他 NMS。