只要你在你的計算機上下載並安裝了 PySNMP 庫,你就可以解決非常基本的 SNMP 問題, 如通過 Python 命令行獲取某個遠程 SNMP Agent 的數據 (你至少需要 4.3.0 以上版本,才可以執行后面的示例代碼)。
復制和粘貼下列代碼到 Python 命令提示符上,代碼將會執行 SNMP GET 操作獲取sysDescr.0
對象,這是一個公開可用的 SNMP Command Responder,
"""
SNMPv1
++++++
Send SNMP GET request using the following options:
* with SNMPv1, community 'public'
* over IPv4/UDP
* to an Agent at demo.snmplabs.com:161
* for two instances of SNMPv2-MIB::sysDescr.0 MIB object,
Functionally similar to:
| $ snmpget -v1 -c public demo.snmplabs.com SNMPv2-MIB::sysDescr.0
"""#
from pysnmp.hlapi import *
errorIndication, errorStatus, errorIndex, varBinds = next(
getCmd(SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
)
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
如果一切執行正常,那么將會在你的終端打印:
...
SNMPv2-MIB::sysDescr."0" = SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m
>>>
想給 """
SNMPv1 TRAP with defaults
+++++++++++++++++++++++++
Send SNMPv1 TRAP through unified SNMPv3 message processing framework
using the following options:
* SNMPv1
* with community name 'public'
* over IPv4/UDP
* send TRAP notification
* with Generic Trap #1 (warmStart) and Specific Trap 0
* with default Uptime
* with default Agent Address
* with Enterprise OID 1.3.6.1.4.1.20408.4.1.1.2
* include managed object information '1.3.6.1.2.1.1.1.0' = 'my system'
Functionally similar to:
| $ snmptrap -v1 -c public demo.snmplabs.com 1.3.6.1.4.1.20408.4.1.1.2 0.0.0.0 1 0 0 1.3.6.1.2.1.1.1.0 s "my system"
"""#
from pysnmp.hlapi import *
errorIndication, errorStatus, errorIndex, varBinds = next(
sendNotification(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 162)),
ContextData(),
'trap',
NotificationType(
ObjectIdentity('1.3.6.1.6.3.1.1.5.2')
).addVarBinds(
('1.3.6.1.6.3.1.1.4.3.0', '1.3.6.1.4.1.20408.4.1.1.2'),
('1.3.6.1.2.1.1.1.0', OctetString('my system'))
)
)
)
if errorIndication:
print(errorIndication)
PySNMP 獲取設備信息示例
2.1. cpu 信息 ¶
根據 UCD-SNMP-MIB 文件,可以獲取的 cpu 參數共有 33 條,這里我們主要關注的是 cpu 的使用率,ssCpuIdle
獲取的是 cpu 的空閑率,所以 100 - ssCpuIdle 既可以求得 cpu 的使用率。
def getCpuUsage(targetHost, targetPort, cmd, community): errIndication, errStatus, errIndex, varBindTable = cmd.nextCmd( cmdgen.CommunityData(community, mpModel=1), # mpModel=1,表示使用v2協議 cmdgen.UdpTransportTarget((targetHost,targetPort)), # 設備ip及端口 cmdgen.MibVariable('UCD-SNMP-MIB','ssCpuIdle'), # 需要訪問信息的MIB庫及子節點,也可以用形如'1.3.6.1.4'(OID標識符)的方式來定義 #lookupValues=True ) if errIndication: print errIndication else: if errStatus: print '%s at %s' % ( errStatus.prettyPrint(), errIndex and varBindTable[-1][int(errIndex)-1] or '?' ) else: return 100.0 - float(varBindTable[0][0][1].prettyPrint())
這是運行結果:
[[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.4.1.2021.11.11.0')), Integer32(92))]] CPU使用率:8.0
2.2. 內存信息 ¶
可以獲取的完整內存對象信息也在http://mibs.snmplabs.com/asn1/UCD-SNMP-MIB
上,包括 memTotalFree,memShared,memBuffer 等。
def getMemUsage(targetHost, targetPort, cmd, community): errIndication, errStatus, errIndex, varBindTable = cmd.nextCmd( cmdgen.CommunityData(community, mpModel=1), cmdgen.UdpTransportTarget((targetHost,targetPort)), cmdgen.MibVariable('UCD-SNMP-MIB','memTotalReal'), #'1.3.6.1.4.1.2021.4.5', cmdgen.MibVariable('UCD-SNMP-MIB','memAvailReal'), #'1.3.6.1.4.1.2021.4.6', cmdgen.MibVariable('UCD-SNMP-MIB','memBuffer'), #'1.3.6.1.4.1.2021.4.14', cmdgen.MibVariable('UCD-SNMP-MIB','memCached'), # '1.3.6.1.4.1.2021.4.15', #cmdgen.MibVariable('UCD-SNMP-MIB', 'memTotalSwap'), #lookupValues=True #lookupNames=True ) #print varBindTable if errIndication: print errIndication else: if errStatus: print '%s at %s' % ( errStatus.prettyPrint(), errIndex and varBindTable[-1][int(errIndex)-1] or '?' ) else: mysum = 0.0 totalAvailReal = float(varBindTable[0][0][1].prettyPrint()) for var in varBindTable: for name , val in var: mysum += float(val.prettyPrint()) return totalAvailReal, (2*totalAvailReal - mysum) / totalAvailReal * 100.0
其中,比較重要的內存信息有:內存總量,緩沖區大小,cache 區大小,swap 區大小等。據此,可以計算出內存的使用率。
2.3. disk 信息 ¶
disk 的相關信息也定義在 mib 文件 UCD-SNMP-MIB 中,根據該文件,可以獲取以下 disk 信息:
DskEntry ::= SEQUENCE { dskIndex Integer32, dskPath DisplayString, dskDevice DisplayString, dskMinimum Integer32, dskMinPercent Integer32, dskTotal Integer32, dskAvail Integer32, dskUsed Integer32, dskPercent Integer32, dskPercentNode Integer32, dskErrorFlag UCDErrorFlag, dskErrorMsg DisplayString, dskTotalLow Unsigned32, dskTotalHigh Unsigned32, dskAvailLow Unsigned32, dskAvailHigh Unsigned32, dskUsedLow Unsigned32, dskUsedHigh Unsigned32 }
根據 oid name,可以很容易看出其意思,下面的代碼可以用來獲取 disk 的使用信息:
def getDiskUsage(targetHost, targetPort, cmd, community): errIndication, errStatus, errIndex, varBindTable = cmd.nextCmd( cmdgen.CommunityData(community, mpModel=1), cmdgen.UdpTransportTarget((targetHost,targetPort)), cmdgen.MibVariable('UCD-SNMP-MIB', 'dskPath'), # '1.3.6.1.4.1.2021.9.1.2' cmdgen.MibVariable('UCD-SNMP-MIB', 'dskTotal'), # '1.3.6.1.4.1.2021.9.1.6' cmdgen.MibVariable('UCD-SNMP-MIB', 'dskPercent'), #'1.3.6.1.4.1.2021.9.1.9' cmdgen.MibVariable('UCD-SNMP-MIB', 'dskDevice'), #'1.3.6.1.4.1.2021.9.1.3' #lookupValues=True, #lookupNames=True ) if errIndication: print errIndication else: if errStatus: print '%s at %s' % (errStatus.prettyPrint(), errIndex \ and varBindTable[-1][int(errIndex)-1] or '?') else: result = [] for var in varBindTable: tempResult = {} for name , val in var: tempResult[name.getLabel()[len(name.getLabel())-1]] = val.prettyPrint() result.append(tempResult) return result
測試時,我們獲取到 waf 設備 10.11.113.150 的 disk 信息為空,其他設備可以正常獲取。
2.4. 流量信息 ¶
也網卡或者流量相關的對象定義定義在 IF-MIB 中,可以獲取的具體信息包括:
IfEntry ::= SEQUENCE { ifIndex InterfaceIndex, ifDescr DisplayString, ifType IANAifType, ifMtu Integer32, ifSpeed Gauge32, ifPhysAddress PhysAddress, ifAdminStatus INTEGER, ifOperStatus INTEGER, ifLastChange TimeTicks, ifInOctets Counter32, ifInUcastPkts Counter32, ifInNUcastPkts Counter32, -- deprecated ifInDiscards Counter32, ifInErrors Counter32, ifInUnknownProtos Counter32, ifOutOctets Counter32, ifOutUcastPkts Counter32, ifOutNUcastPkts Counter32, -- deprecated ifOutDiscards Counter32, ifOutErrors Counter32, ifOutQLen Gauge32, -- deprecated ifSpecific OBJECT IDENTIFIER -- deprecated }
以下是獲取網卡流量相關信息的示例代碼:
def getIfaceTraffic(targetHost, targetPort, cmd, community, period): def getNowTraffic(): errIndication, errStatus, errIndex, varBindTable = cmd.nextCmd( cmdgen.CommunityData(community, mpModel=1), cmdgen.UdpTransportTarget((targetHost,targetPort)), cmdgen.MibVariable('IF-MIB', 'ifDescr'), # '1.3.6.1.2.1.2.2.1.2' cmdgen.MibVariable('IF-MIB', 'ifInOctets'), # '1.3.6.1.2.1.2.2.1.10' cmdgen.MibVariable('IF-MIB', 'ifOutOctets'), #'1.3.6.1.2.1.2.2.1.16' #lookupValues=True, #lookupNames=True ) if errIndication: print errIndication else: if errStatus: print '%s at %s' % (errStatus.prettyPrint(), errIndex \ and varBindTable[-1][int(errIndex)-1] or '?') else: result = [] #print varBindTable for var in varBindTable: tempResult = {} for name , val in var: tempResult[name.getLabel()[len(name.getLabel())-1]] = val.prettyPrint() result.append(tempResult) return result preTraffic = getNowTraffic() #print preTraffic time.sleep(period) afterTraffic = getNowTraffic() #print afterTraffic traffic = [] if(len(preTraffic) != len(afterTraffic)): return None else: ifaceNum = len(preTraffic) for i in range(ifaceNum): if preTraffic[i]['ifDescr'] == afterTraffic[i]['ifDescr']: m = float(preTraffic[i]['ifInOctets']) mm = float(afterTraffic[i]['ifInOctets']) n = float(preTraffic[i]['ifOutOctets']) nn = float(afterTraffic[i]['ifOutOctets']) ifaceName = preTraffic[i]['ifDescr'] traffic.append({ 'ifaceName':ifaceName, 'inTraffic(Mbps)':(mm-m)/period/1048576*8, 'outTraffic(Mbps)':(nn-n)/period/1048576*8 }) else: return None return traffic