PySNMP中文6、常用操作

安裝

安裝pysnmp

pip install pysnmp -i https://pypi.douban.com

安裝pysnmp-mibs

pip install pysnmp-mibs

常用操作

在本教程中,我們將逐步創建和運行幾個不同的SNMP命令請求和通知。我們將使用PySNMP同步高級API hlapi,這是最簡單的使用。

創建SNMP Engine

SNMP引擎是PySNMP中的一箇中心傘形對象。所有的PySNMP操作都涉及 SnmpEngine類實例。PySNMP應用程序可以運行多個獨立的SNMP引擎,每個引擎由它自己的SnmpEngine對象引導。

>>> from pysnmp.hlapi import *
>>>
>>> SnmpEngine()
SnmpEngine(snmpEngineId=OctetString(hexValue='80004fb80567'))

SNMP引擎具有可自動或者手動分配的唯一標識符。此標識符用於SNMP協議操作。

查詢SNMP

我們發送SNMP GET命令去SNMP agent讀取一個MIB對象。爲此,我們將調用同步的高級的 getCmd()方法。通過調用相應的函數,可以以不同的類似方式使用其他SNMP命令。

>>> from pysnmp.hlapi import *
>>> [ x for x in dir() if 'Cmd' in  x ]
['bulkCmd', 'getCmd', 'nextCmd', 'setCmd']
>>> getCmd
<function getCmd at 0x222b330>

選擇SNMP協議和憑證

我們可以選擇三種SNMP協議版本。爲了使用SNMP的版本1或者2c,我們需要傳遞正確初始化的CommunityData類的實例。對於第三個版本,我們需要傳遞 UsmUserData 類的實例

SNMP共同體名以及SNMP v1和v2c之間的選擇通過 CommunityData 對象傳遞給SNMP LCD。

>>> from pysnmp.hlapi import *
>>>
>>> CommunityData('public', mpModel=0) # SNMPv1
CommunityData('public')
>>> CommunityData('public', mpModdel=1) # SNMPv2
CommunityData('public')

使用 UsmUserData 對象進行LCD配置意味着使用SNMPv3。除了設置USM用戶名之外,UsmUserData 對象還可以將密碼密鑰和密碼協議傳輸到SNMP配置LCD。

>>> from pysnmp.hlapi import *
>>>
>>> UsmUserData('testuser', authKey='myauthkey')
UsmUserData(userName='testuser', authKey=<AUTHKEY>)
>>> UsmUserDdata('testuser', authKey='myauthkey', privKey='myencky')
UsmUserData(userName='testuser', authKey=<AUTHKEY>, privKey=<PRIVKEY>)

PySNMP支持MD5和SHA消息授權算法,DES,AES128/192/256 和 3DES加密算法。
爲了簡單起見,我們使用SNMPv2。儘管不太安全,但它仍然是最流行的版本。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(), CommunityData('public'),
...

設置傳輸和目標target

PySNMP支持UDP-over-IPv4和UDP-over-IPv6網絡傳輸。在本例中,我們將通過Internet上調度IPv4在 demo.snmplabs.com 上查詢可用的公告SNMP模擬器。傳輸配置分別以正確初始化的 UdpTrasportTarget 或者 Udp6TransportTarget 對象的形式傳遞給SNMP LCD。

>>> from pysnmp.hlapi imort *
>>>
>>> g = getCmd(SnmpEngine(),
· · ·                    CommunityData('public'),
· · ·                    UdpTransportTarget(('demo.snmplabs.com', 161)),
· · ·

addressing SNMP context:調用SNMP上下文

SNMP上下文是SNMP(v3)消息頭中的一個參數,它處理SNMP引擎在託管實體上提供的MIB的特定集合。SNMP引擎可以爲許多相同的MIB對象提供服務,這些對象表示被管理的硬件或軟件的完全不同的實例。這裏可以用SNMP上下文。
爲了在高級API hlapi中指示SNMP上下文,應該使用正確初始化的ContextData對象。對於本例,我們將使用“empty”上下文(默認)

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
· · ·                    CommunityData('public'),
· · ·                    UdpTransportTarget(('demo.snmplabs.com', 161)),
· · ·                    ContextData(),
· · ·

Specifying MIB object:指定MIB對象

最後,我們必須指定要讀取的MIB對象。在協議層上,MIB對象由OIDs標識,但人們傾向於通過名稱來調用它們,哈哈哈!

$ snmpget -v2c -c public demo.snmplabs.com SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: SunOS zeus.snmplabs.com
$
$ snmpget -v2c -c public demo.snmplabs.com 1.3.6.1.2.1.1.1.0
SNMPv2-MIB::sysDescr.0 = STRING: SunOS zeus.snmplabs.com

對象名稱和OID都來自MIB。名稱和OID鏈接由稱爲對象類型的高級SMI構造完成。下面是一個示例MIB對象頂一頂sysUpTime與OID…mgmt.mib-2.system.3 值的類型爲 TimeTicks

sysUpTime OBJECT-TYPE
    SYNTAX          TimeTicks
    MAX-ACCESS    read-only
    STATUS           current
    DESCRIPTION
        "The time (in hundredths of a second) since the network management portion of the system was last re-initialized."
    :: = { system 3 }

在PySNMP中,我們使用負責MIB對象標識的 ObjectIdentity 類。ObjectIdentity標識從人的角度處理MIB對象的方法。它需要諮詢MIB才能進入完全“解決”的狀態。ObjectIdentity可以使用MIB對象名進行初始化,在進行MIB查找之後,它將開始執行類似於OID的操作。

>>> from pysnmp.hlapi import *
>>>
>>> x = ObjectIdentity('SNMPv2-MIB', 'system')
>>> # . . . calling MIB lookup . . .
>>> tuple(x)
(1, 3, 6, 1, 2, 1, 1, 1)
>>> x = ObjectIdentity('iso.org.dod.internet.mgmt.mib-2.system.sysDdescr')
>>> # . . . calling MIB lookup . . .
>>> str(x)
'1.3.6.1.2.1.1.1'

calling MIB lookup類似如下

from pysnmp.smi import builder, view

mib_builder = builder.MibBuilder()
mib_view = view.MibViewController(mib_builder)
mib_var = ObjectIdentity('SNMPv2-MIB', 'system', '0')
mib_var.resolveWithMib(mib_view)

print tuple(mib_var)
print str(mib_var)

MIB解析是指將MIB對象名稱到OID的轉換,反之亦然。

ObjectType 類的實例標識PySNMP中的對象類型SMI的構造。ObjectType是引用ObjectIdentity和SNMP類型實例的容器對象。作爲一個Python對象,它看起來像一個(OID, value)元組。

>>> from pysnmp.hlapi import *
>>> x = ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386 box'))
>>> # . . . calling MIB lookup . . .
>>> x[0].prettyPrint()
'SNMPv2-MIB::sysDescr.0'
>>> x[1].prettyPrint()
'Linux i386 box'

末尾的零表示MIB對象的實例。MIB中描述的對象指示聲明,它們從來不包含任何數據。數據存儲在MIB對象的實例中,通過向MIB對象標識符附加額外信息(稱爲索引)來尋址。
對於標量MIB對象,按照慣例索引是’0’。ObjectIdentity類將索引作爲其初始化器。

>>> x = ObjectIdentity('SNMPv2-MIB', 'system', 0)
>>> # ... calling MIB lookup ...
>>> tuple(x)
(1, 3, 6, 1, 2, 1, 1, 1, 0)

我們將讀取在SNMPv2-MIB模塊中定義的 sysDesc 標量MIB對象的實例。

>>> from pysnmp.hlapi import *
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))

默認情況下,PySNMP將在你的本地的文件系統中搜索你所引用的ASN.1 MIB文件。還可以將其配置爲從遠程主機自動下載,如示例所示。我們維護了一個ASN.1 MIB模塊的集合,你可以在你的SNMP項目中使用它。

note:
一個“ASN.1 MIB”是一個iddentifier和types的純文本描述。它是製造商用來描述其SNMP服務的通用格式,與Perl的Net::SNMP和幾乎所有SNMP工具使用的格式相同。

Reading scalar value

我們終於可以發送SNMP查詢並希望收到一些有意義的響應。
同步API的獨特之處在於它是圍繞Python生成器的思想構建的。任何函數調用都以生成器對象結束。死給!對生成器對象的迭代執行實際的SNMP通信。在每次構建和發送SNMP消息時,都要等待、接受和解析響應。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
...            CommunityData('public'),
...            UdpTransportTarget(('demo.snmplabs.com', 161)),
...            ContextData(),
...            ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime', 0)))
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(44430646))])

Working with SNMP tables

SNMP定義了表的概念,當一個給定的MIB對象將應用於一個屬性的多個實例時,將使用表。例如,將網絡接口的屬性放到SNMP表中。屬性的每個實例都由附加到MIB對象的後綴來尋址。
表再MIBs中指定,它們的索引通過INDEX語句聲明。表索引是非零整數、字符串或任何基本SNMP類型。
在協議層,所有的索引都是OID的一部分。爲了方便人們使用索引,SNMP管理應用程序用DISPLAY-HINT子句來實現OID和SNMP類型之間的自動索引轉換。

ifEntry OBJECT-TYPE
    SYNTAX      IfEntry
    INDEX   { ifIndex }
::= { ifTable 1 }

ifIndex OBJECT-TYPE
    SYNTAX      InterfaceIndex
::= { ifEntry 1 }

ifDescr OBJECT-TYPE
    SYNTAX      DisplayString (SIZE (0..255))
::= { ifEntry 2 }

InterfaceIndex ::= TEXTUAL-CONVENTION
    DISPLAY-HINT "d"
    SYNTAX       Integer32 (1..2147483647)

PySNMP的用法是:

>>> x = ObjectIdentity('IF-MIB', 'ifDescr', 123)
>>> # . . . calling MIB lookup . . .
>>> str(x)
'1.3.6.1.2.1.2.2.1.2.123'

有些SNMP表有許多索引。這些索引中的每一個都成爲OID的一部分,彼此相連,並最終連接到MIB對象的OID。
從語義的角度看,每個索引都反映了一個MIB對象重要而獨特的屬性。

tcpConnectionEntry OBJECT-TYPE
    SYNTAX  TcpConnectionEntry
    INDEX   { tcpConnectionLocalAddressType,
              tcpConnectionLocalAddress,
              tcpConnectionLocalPort,
              tcpConnectionRemAddressType,
              tcpConnectionRemAddress,
              tcpConnectionRemPort }
::= { tcpConnectionTable 1 }

tcpConnectionLocalPort OBJECT-TYPE
    SYNTAX     InetPortNumber
::= { tcpConnectionEntry 3 }

PySNMP的 ObjectIdentity這個類以易讀的方式接收任意數量的索引,並將他們轉換爲OID。

>>> x = ObjectIdentity('TCP-MIB', 'tcpConnectionState',
. . .                           'ipv4', '195.218.254.105', 41511,
. . .                           'ipv4', '194.67.1.250', 993)
>>> # . . . calling MIB lookup . . .
>>> str(x)
'1.3.6.1.2.1.6.19.1.7.1.4.195.218.254.105.41511.1.4.194.67.1.250.993'

來讀取TCP-MIB::tcpConnectionState 這個對象:

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
. . .                   CommunityData('public'),
. . .                   UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                   ContextData(),
. . .                   ObjectType(ObjectIdentity('TCP-MIB', 'tcpConnectionState', 
. . .                                                      'ipv4', '195.218.254.105', 41511,
. . .                                                      'ipv4', '194.67.1.250', 993)
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.6.19.1.7.1.4.195.218.254.105.41511.1.4.194.67.1.250.993')), Integer(5))])

SNMP command operations:SNMP命令操作

SNMP允許你請求一個MIB對象,通過next獲取下一個值。通過這種方式,你可以提前讀取你不知道的MIB對象。MIB對象根據它們的OID進行概念排序。這個功能由 nextCmd() 函數實現。

>>> from pysnmp.hlapi import *
>>> g = nextCmd(SnmpEngine(),
. . .                     CommunityData('public'),
. . .                     UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                     ContextData(),
. . .                     ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')))
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com'))])
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.2.0'), ObjectIdentity(ObjectIdentifier('1.3.6.1.4.1.8072.3.2.10')))])

對生成器對象的迭代遍歷了SNMP agent的MIB對象s。

SNMPv2爲GETNEXT命令引入了重要的優化——修改後叫GETBULK,能立即收集和響應一組“下一個”MIB對象。附加的非重複器和大量重複參數可用於影響MIB對象的批處理。

PySNMP在協議級別隱藏了GETBULK的優化,爲了方便,bulkCmd()函數公開了和getNext()相同的生成器API。

>>> from pysnmp.hlapi imort *
>>>
>>> N, R = 0, 25
>>> g = bulkCmd(SnmpEngine(),
. . .                     CommunityData('public'),
. . .                     UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                     ContextData(),
. . .                     N, R,
. . .                     ObjectType(ObjectIdentity('1.3.6')))
>>>
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com'))])
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.2.0'), ObjectIdentifier('1.3.6.1.4.1.20408'))])

Python生成器不僅可以生成數據,還可以將數據發送到正在運行的生成器對象中。高級API hlapi使用該特性對一組新的MIB對象重複相同的SNMP操作。

>>> from pysnmp.hlapi import *
>>>
>>> g = nextCmd(SnmpEngine(),
. . .                     CommunityData('public'),
. . .                     UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                     ContextData(),
. . .                     ObjectType(ObjectIdentity('IF-MIB', 'ifTable')))
>>>
>>> g.send([ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets'))])
(None, 0, 0, [(ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))])

你可以通過在一個PDU中列出許多不相關的MIB對象來操作它們。響應PDU將攜帶一個MIB對象列表及其值,其順序與請求消息中的順序完全相同。

>>> from pysnmp.hlapi import *
>>>
>>> g = getCmd(SnmpEngine(),
. . .                   CommunityData('public'),
. . .                   UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                   ContextData(),
. . .                   ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)),
. . .                   ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime', 0))
. . . )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('SunOS zeus.snmplabs.com')), ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(44430646))])

SNMP的配置管理部分依賴於SNMP SET命令。儘管它在被管理實體上的實現被證明是有些苛刻的(由於鎖和事務行爲需求)。因此,供應商傾向於將其排除在外,從而將託管實體呈現爲只讀。
PySNMP通過 setCmd() 函數統一支持設置。

>>> from pysnmp.hlapi import *
>>>
>>> g = setCmd(SnmpEngine(),
. . .                   CommunityData('public'),
. . .                   UdpTransportTarget(('demo.snmplabs.com', 161)),
. . .                   ContextData(),
. . .                   ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386')
. . . )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), DisplayString('Linux i386'))])

sending SNMP notifications:發送SNMP通知

託管實體可以向管理實體發送未經請求的消息。在SNMP中稱爲通知notification。通知有助於減少輪詢,輪詢在大型網絡中是一個麻煩的問題。
SNMP通知是枚舉的,每個通知都有明確的語義。這是通過一種稱爲NOTIFICATION-TYPE的特殊高級SMI構造實現的。與定義MIB對象的 OBJECT-TYPE一樣,NOTIFICATION-TYPE也有唯一的OID,但是它引用的是其他的MIB對象序列,而不是SNMP值。這些MIB對象由OBJECTS子句指定,當發送通知時,它們的當前值包含在通知消息中。

linkUp NOTIFICATION-TYPE
    OBJECTS { ifIndex, ifAdminStatus, ifOperStatus }
    STATUS  current
    DESCRIPTION
        "..."
::= { snmpTraps 4 }

爲了在PySNMP中建模NOTIFICATION-TYPE結構,我們有一個Notification Type類的容器對象。它由ObjectIdentity 類標識,並引用 ObjectType 類的實例的序列。

從行爲的角度來看,NotificationType類似於ObjectType類實例的序列。

>>> from pysnmp.hlapi import *
>>>
>>> x = NotificationType(ObjectIdentity('IF-MIB', 'linkUp'))
>>> # . . . calling MIB lookup . . .
>>>
>>> [ str(y) for x in n ]['SNMPv2-MIB::snmpTrapOID.0 = 1.3.6.1.6.3.1.1.5.3', 'IF-MIB::ifIndex = ', 'IF-MIB::ifAdminStatus = ', 'IF-MIB::ifOperStatus = ']

使用PySNMP發送通知與發送SNMP命令沒有太大的區別。區別在於PDU綁定的構建方式。SNMP中有兩種不同的通知,trap和inform。
在trap中,agent-to-manager 是單向的,不發生響應或確認消息。

>>> from pysnmp.hlapi import *
>>>
>>> g = sendNotification(SnmpEngine(),
. . .                      CommunityData('public'),
. . .                      UdpTransportTarget(('demo.snmplabs.com', 162)),
. . .                      ContextData(),
. . .                      'trap',
. . .                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,))
. . . )
>>> next(g)
(None, 0, 0, [])

inform通知很像命令。區別在於PDU格式。Inform用於manager-to-manager通信以及agent-to-manager通信。

>>> from pysnmp.hlapi import *
>>>
>>> g = sendNotification(SnmpEngine(),
. . .                      CommunityData('public'),
. . .                      UdpTransportTarget(('demo.snmplabs.com', 162)),
. . .                      ContextData(),
. . .                      'inform',
. . .                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,))
. . . )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(0)), ObjectType(ObjectIdentity('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentity('1.3.6.1.6.3.1.1.5.4')), ObjectType(ObjectName('1.3.6.1.2.1.2.2.1.1.123'), Null('')), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.7.123'), Null('')), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.8.123'), Null(''))])

在後一個示例中,可以看到MIB對象(ifIndex、ifAdminStatus、ifOperStatus)從IF-MIB::linkUp通知自動展開。
要按索引查找SNMP表對象的特定行,可以通過instanceIndex參數將MIB對象的索引部分傳遞給NotificationType。

如你所見,擴展的MIB對象的實際值是NULLs。這是因爲在這些示例中,我們的簡單腳本不能訪問那些MIB對象。我們可以通過傳遞NotificationType 對象來提供丟失的信息,該對象將MIB對象OID映射到當前值。

>>> from pysnmp.hlapi import *
>>>
>>> mib = {ObjectIdentifier('1.3.6.1.2.1.2.2.1.1.123'): 123,
. . .        ObjectIdentifier('1.3.6.1.2.1.2.2.1.7.123'): 'testing',
. . .        ObjectIdentifier('1.3.6.1.2.1.2.2.1.8.123'): 'up'}
>>>
>>> g = sendNotification(SnmpEngine(),
. . .                      CommunityData('public'),
. . .                      UdpTransportTarget(('demo.snmplabs.com', 162)),
. . .                      ContextData(),
. . .                      'inform',
. . .                      NotificationType(ObjectIdentity('IF-MIB', 'linkUp'), instanceIndex=(123,), objects=mib)
. . . )
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity('1.3.6.1.2.1.1.3.0'), TimeTicks(0)), ObjectType(ObjectIdentity('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentity('1.3.6.1.6.3.1.1.5.4')), ObjectType(ObjectName('1.3.6.1.2.1.2.2.1.1.123'), InterfaceIndex(123)), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.7.123'), Integer(3)), ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1.8.123'), Integer(1))])

High-volume messaging

在管理大型網絡時,按順序讀取MIB對象會導致延遲。在某個時間點,延遲變得無法忍受。並行化查詢的解決方案是衆所周知的——您可以通過將單個操作轉移到多個進程或多個執行線程中,或者圍繞異步I/O模型構建應用程序來實現這一點。

與其他解決方案相比,異步模型是最輕量級和可伸縮的。這個想法很簡單:永遠不要等待I/O——只要可能,就做其他事情。這背後的問題是,執行流變成了非線性的,這影響了人類讀者對程序的分析。

PySNMP高級API採用了三種流行的異步I/O框架——asyncore、twisted和asyncio。有關異步API的更多信息,請參閱PySNMPlibrary referenceexample

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章