SNMP ,簡稱簡單網路管理協議,是 SDN 的必備工具,是軟體控制設備的最佳選擇。即使除此之外,應用內訪問也是 SNMP 的主要目的。毫無疑問,所有監控系統都利用 SNMP 來監控伺服器和網路設備。在腳本中擁有來自 SNMP 的巨大力量將是驚人的。因此,我們將在本教程中討論 SNMP 在 Python 編程語言中的使用。
但是在我們開始之前,讓我們討論一下 SNMP。
了解簡單網路管理協議
SNMP ,也稱為簡單網路管理協議,是管理伺服器和遠程設備(代理)之間進行通信的標準方式。SNMP 的目標是讓管理人員了解(甚至更改)代理上的數據。例如,管理器可以檢查哪些介面是打開的,哪些是關閉的,或者更改遠程設備的主機名。
我們的腳本使管理站上的 Python 程序能夠控制執行 SNMP 代理的遠程設備。
SNMP 代理在一個特殊的表 MIB 中準備了管理器可以讀取或更改的大部分細節。MIB 是一個樹狀結構,其中一個數字表示樹中的每個節點。例如 1.3.6.1.2.1.1 表示系統的描述。如果我們中的一些人想知道這個數字鏈是從哪裡來的,這就是整個樹的結構!每個數字都與一個名字相關聯。因此,我們可以把它翻譯成更明確的iso . org . DOD . internet . mgmt . MIB-2 . system . SysDerse。
現在,讓我們藉助 Python PySNMP 模塊來討論 SNMP 在 Python 編程語言中的使用。
了解 PySNMP 模塊
PySNMP 是 Python 的開源模塊。與 telnet 或 HTTP 不同,Python 本身並不實現 SNMP。畢竟,僅僅是網路和系統工程師就需要工廠里有一個 Python 開發人員。 PySNMP 很好地彌補了原生 Python 的不足。總的來說,SNMP模塊允許我們使用任何版本的 SNMP,既可以作為代理,也可以作為管理器。創建代理意味著我們正在構建應用或設備。然而,我們將只討論 PySNMP 在管理遠程設備中的使用。
而且,我們會了解 Python 中 PySNMP 的不同功能。本教程的主要目標是創建一個快速的 python 程序,使我們的工作變得簡單。在程序中,我們將擁有所需的所有 SNMP 操作。
所以,讓我們開始吧。
準備環境
首先我們要安裝 PySNMP 模塊。我們可以使用 pip 安裝程序,在以下命令的幫助下安裝所需的模塊。
語法:
$ pip install pysnmp
該模塊將作為 Python 和 pip 版本安裝在系統中。
驗證安裝
為了檢查模塊是否已經正確安裝在系統中,我們可以嘗試導入模塊並執行程序。
安裝完成後,創建一個新的 Python 文件,並在其中鍵入以下語法。
示例:
# importing the required module
import pysnmp
現在,保存該文件並在命令提示符下使用以下命令運行該文件。
語法:
$ python .py
如果程序運行時沒有出現任何導入錯誤,則模塊安裝正確。否則,建議重新安裝該模塊,並參考其官方文檔。
理解 Python SNMP 獲取操作
SNMP 的 Get 操作使我們能夠檢索 MIB 中單個對象的值。我們還可以利用它來獲得單個對象的列表。我們可以開始寫出如下所示的 get() 函數:
示例:
# importing the required module
from pysnmp import hlapi
# defining the get() function
def get(
target,
oids,
credentials,
port = 161,
engine = hlapi.SnmpEngine(),
context = hlapi.ContextData()
):
handler = hlapi.getCmd(
engine,
credentials,
hlapi.UdpTransportTarget((target, port)),
context,
*construct_object_types(oids)
)
return fetch(handler, 1)[0]
說明:
從上面的代碼片段中,我們可以觀察到 PySNMP 的高級 API 的槓桿作用。我們定義了一個簡單的函數 get() ,它首先需要一個目標(IP 或遠程設備名)。然後,它需要我們需要獲取的對象標識(oid)列表,然後是一組用於會話身份驗證的憑據。如果需要,我們還可以指定一個不同的 UDP 埠,並利用流行的 SNMP 引擎或自定義上下文。我們可能需要對同一設備上的所有操作使用相同的引擎,這樣可以節省資源。但是,對於一個簡單的代碼片段來說,這不是必需的,這樣我們就可以忽略兩個引擎以及上下文。
該函數為 SNMP 會話生成一個處理程序,並從中獲取詳細信息。為了實現這一點,它依賴於我們必須創建的兩種方法:構造 對象 類型和獲取。
構造對象類型
正如我們之前討論的,擁有更多的力量意味著更多的複雜性。因此, hlapi.getCmd() 函數需要一些特殊的 hlapi。ObjectType 對象,而不是簡單的字元串 oid 列表。因此, construct_object_type 函數根據 PySNMP 的需要創建。如果沒有時間,我們可以簡單地複製並粘貼到代碼中。然而,這應該是一個非常簡單的功能;讓我們來看看:
示例:
def construct_object_types(listOfOids):
objectTypes = []
for oid in listOfOids:
objectTypes.append(hlapi.ObjectType(hlapi.ObjectIdentity(oid)))
return objectTypes
說明:
上面的代碼片段返回了一個列表,可以通過在前面加上一個*進行擴展,就像我們在 get() 方法中所做的那樣。
正在獲取數據
fetch() 函數是 Python SMP 教程的傑作。總的來說,我們編寫它是為了可以將其重新用於基於 PySNMP 的其他功能,比如 get-bulk。它只是根據計數變數在處理程序上循環多次。如果出現任何錯誤,將停止該過程,並返回運行時間錯誤消息。在其他情況下,它將數據存儲在字典列表中。
示例:
def fetch(handler, count):
res = []
for i in range(count):
try:
error_indication, error_status, error_index, var_binds = next(handler)
if not error_indication and not error_status:
items = {}
for var_bind in var_binds:
items[str(var_bind[0])] = cast(var_bind[1])
res.append(items)
else:
raise RuntimeError('Got SNMP error: {0}'.format(error_indication))
except StopIteration:
break
return res
說明:
在上面的代碼片段中,我們構建了try-除了方法,為了特定的原因停止迭代。在用戶指定的計數高於我們實際擁有的對象數量的情況下,我們只需停止並返回到目前為止得到的結果。這就是構造的目的。
返回字典列表的需求是什麼?在每個 get 操作中,我們可以得到各種各樣的對象 id。因此,每個字典都將由作為關鍵字的對象標識和作為該關鍵字值的管理信息庫中的 OID 值組成。在一次獲取中需要多個 oid 的場景中,我們將返回一個帶有多個鍵的字典。但是,有什麼必要列出清單呢?使用 get 操作,我們只能檢索一次數據。然而,正如我們將在 get bulk 中看到的,我們可能需要在不同的實例上多次獲得類似的細節。讓我們考慮一個更好理解的例子。假設我們需要檢查所有介面上的錯誤:信息總是錯誤;然而,我們有不同的實例(每個介面一個)。我們可以使用列表來可視化它,其中每個數據元素都是描述一個實例的字典。
注意:fetch()函數依賴於我們必須創建的另一個函數:cast()。該函數將從 PySNMP 接收的數據轉換為 int、float 或 string。
讓我們考慮下面的代碼片段:
示例:
def cast(val):
try:
return int(val)
except (ValueError, TypeError):
try:
return float(val)
except (ValueError, TypeError):
try:
return str(val)
except (ValueError, TypeError):
pass
return val
說明:
在上面的代碼片段中,我們定義了一個函數,其中我們使用了try-除了方法來檢查任何引發的錯誤。
提供憑據
PySNMP 庫的認證系統很強大,也很簡單。沒有理由在上面額外寫一層,這樣我們就可以直接利用它。 get() 函數與其他函數一樣,在憑證變數中有一個特殊的身份驗證對象。如果我們使用 SNMPv2c 或 SNMPv3,這個對象是變化的。
在 SNMPv2c(或更低)的情況下,我們必須指定社區。我們可以使用社區數據對象來實現,如下所示:
語法:
hlapi.CommunityData('JAVATPOINT')
相反,SNMPv3 很複雜。這是因為它利用了一個有兩個密碼和兩個協議的用戶:第一個用於身份驗證,另一個用於加密。因此,我們必須指定用戶名、驗證密碼、驗證協議、加密密碼和加密協議。我們可以使用 UsmUserData 類來實現。
為了更好地理解,讓我們考慮下面的例子。
示例:
hlapi.UsmUserData(
'testuser',
authKey = 'authenticationkey',
privKey = 'encryptionkey',
authProtocol = hlapi.usmHMACSHAAuthProtocol,
privProtocol = hlapi.usmAesCfb128Protocol
)
說明:
在上面的代碼片段中,我們使用了 UsmUserData 類並輸入了所需的細節。它比看起來簡單;我們必須知道遠程設備的協議。然而,我們中的一些人可能會參考 UsmUserData 上的完整官方文檔。
獲取主機名
現在,讓我們測試一下 get() 功能。我們將使用它來檢索設備的主機名,即對象 1.3.6.1.2.1.1.5.0。我們可以簡單地編寫以下代碼片段:
示例:
print(get('10.0.0.1', ['1.3.6.1.2.1.1.5.0'], hlapi.CommunityData('JAVATPOINT')))
輸出:
{'1.3.6.1.2.1.1.5.0': 'R1.sdn.local'}
說明:
在上面的代碼片段中,我們列印了 get() 函數獲取設備主機名的結果。
注意:在這裡,我們沒有得到字典的列表,而只是一個字典。這是經過深思熟慮的,get()函數在任何時候都是這樣的。一般我們知道函數只執行一次;它不能創建多個實例。因此,我們返回從 fetch()獲得的第一個元素。
理解 Python SNMP 批量獲取
get_bulk() 方法檢索同一個對象標識的多個實例,假設每個介面一個。當我們使用表時,這個函數變得可支持,比如介面一的路由表。它相當簡單,功能類似於 get() 方法。但是它需要一些額外的細節:從哪個對象開始,以及我們需要獲得的實例數量。我們在從開始發貨,從算起。
讓我們考慮以下代碼片段來理解 get_bulk() 函數的工作原理。
示例:
def get_bulk(
target,
oids,
credentials,
count,
start_from = 0,
port = 161,
engine = hlapi.SnmpEngine(),
context = hlapi.ContextData()):
handler = hlapi.bulkCmd(
engine,
credentials,
hlapi.UdpTransportTarget(( target, port )),
context,
start_from, count,
*construct_object_types( oids )
)
return fetch(handler, count)
說明:
在上面的代碼片段中,我們定義了 get_bulk() 函數,在這裡我們指定了處理程序。最後,我們返回了 fetch() 功能。因此,我們需要一個字典列表,所以我們不必像使用 get() 函數那樣只提取第一個字典。
理解 Python SNMP 獲取批量自動
get_bulk_auto() 功能是 get_bulk() 功能的改進版。假設我們想使用 get_bulk() 循環訪問設備介面。我們如何知道介面的數量?這是必要的,因為 SNMP 需要知道迭代多少次。我們不能提前知道;但是,我們可以使用 SNMP 作為一個選項來查找這些信息。
我們可以使用 get_bulk_auto() 函數告訴代碼從另一個 OID 中檢索計數變數。因此,我們可以指定一個對象標識,而不是指定一個數字。該函數將獲取該對象,並將其用作計數。
為了更好地理解,讓我們考慮下面的例子。
示例:
def get_bulk_auto(
target,
oids,
credentials,
count_oid,
start_from = 0,
port = 161,
engine = hlapi.SnmpEngine(),
context = hlapi.ContextData()):
count = get(
target,
[count_oid],
credentials,
port,
engine,
context
)[count_oid]
return get_bulk(target, oids, credentials, count, start_from, port, engine, context)
說明:
在上面的代碼片段中,我們定義了 get_bulk_auto() 函數,並使用 get() 指定了計數變數,並返回 get_bulk() 函數。
使用 Python SNMP 批量獲取和批量自動獲取
讓我們考慮執行下面的代碼片段。
示例:
ele = get_bulk_auto(
'10.0.0.1',
['1.3.6.1.2.1.2.2.1.2 ', '1.3.6.1.2.1.31.1.1.1.18'],
hlapi.CommunityData('JAVATPOINT'),
'1.3.6.1.2.1.2.1.0')
for i in ele:
for x, y in i.items():
print("{0} = {1}".format(x, y))
print('')
輸出:
1.3.6.1.2.1.2.2.1.2.1=FastEthernet1/0
1.3.6.1.2.1.31.1.1.1.18.1=
1.3.6.1.2.1.2.2.1.2.2=FastEthernet0/0
1.3.6.1.2.1.31.1.1.1.18.2=
1.3.6.1.2.1.2.2.1.2.3=FastEthernet0/1
1.3.6.1.2.1.31.1.1.1.18.3=Test Desc
1.3.6.1.2.1.2.2.1.2.4=Serial2/0
1.3.6.1.2.1.31.1.1.1.18.4=
1.3.6.1.2.1.2.2.1.2.5=Serial2/1
1.3.6.1.2.1.31.1.1.1.18.5=
1.3.6.1.2.1.2.2.1.2.6=Serial2/2
1.3.6.1.2.1.31.1.1.1.18.6=
1.3.6.1.2.1.2.2.1.2.7=Serial2/3
1.3.6.1.2.1.31.1.1.1.18.7=
1.3.6.1.2.1.2.2.1.2.9=Null0
1.3.6.1.2.1.31.1.1.1.18.9=
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/277280.html