PySNMP获取设备信息

1.1. 快速入门

只要你在你的计算机上下载并安装了 PySNMP 库,你就可以解决非常基本的 SNMP 问题, 如通过 Python 命令行获取某个远程 SNMP Agent 的数据 (你至少需要 4.3.0 以上版本,才可以执行后面的示例代码)。

1.1.1. 获取 SNMP 变量

复制和粘贴下列代码到 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
>>>

1.1.2. 发送 SNMP TRAP

想给 demo.snmplabs.com 中列出的宿主 Notification Receiver 发送 TRAP 消息,复制以下代码到你的交互式 Python 会话中。"""

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

 




 

posted @ 2022-03-21 19:18  游走De提莫  阅读(974)  评论(0编辑  收藏  举报