Python通過SNMP監控網絡設備


前段時間,為了實現自動化巡檢,我開發了自動化巡檢工具,由於我的系統設備版本比較多,所以我是分別開發的客戶端程序,服務端使用dll文件與客戶端通信,服務端的dll在與python通信,通過Python豐富的第三方庫,實現繪圖入庫等,該方式比較繁瑣,我們管理的設備還有一些網絡設備,這些設備無法通過開發程序來實現監控,為了實現全平台全設備監控,我決定使用SNMP實現監控任務。

首先需要在系統中安裝SNMP客戶端,對於Linux平台來說只需要執行如下配置過程即可.

[root@localhost ~]# yum install -y net-snmp
[root@localhost ~]# cat /etc/snmp/snmpd.conf |grep -vE "^#|^$"
com2sec notConfigUser  default       public

group   notConfigGroup v1           notConfigUser
group   notConfigGroup v2c           notConfigUser

view    systemview    included   .1
view    systemview    included   .1

access  notConfigGroup  ""  any  noauth  exact  systemview none none

[root@localhost ~]# systemctl restart snmpd
[root@localhost ~]# systemctl enable snmpd

如果是Windows系統則需要在客戶機服務列表,開啟SNMP支持,並設置好一個團體名稱,如下圖。

當我們配置好客戶端后,服務端就客戶獲取數據了,我們以一個OID序號為例,我們查詢特定序號對應的名稱,然后將其記錄下來,例如下面這樣。

首先我們不適用PySNMP模塊直接開線程調用看看,該代碼如下所示.

import os,re,time

# 通過SNMP收集主機CPU利用率: 通過SNMP協議,收集目標主機的CPU利用率(百分比),並返回JSON字符串.
def Get_CPU_Info(addr):
    try:
        Head = ["HostName","CoreLoad","CpuUser","CpuSystem","CpuIdle"]
        CPU = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        CPU.append(ret.read().split(":")[3].strip())
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.25.3.3.1.2")
        CPU.append(ret.read().split(":")[3].strip())

        for i in [9,10,11]:
            ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " 1.3.6.1.4.1.2021.11.{}.0".format(i))
            ret = ret.read()
            Info = ret.split(":")[3].strip()
            CPU.append(Info)
        return dict(zip(Head,CPU))
    except Exception:
        return 0

# 通過SNMP獲取系統CPU負載信息: 分別獲取到系統的1,5,15分鍾的負載信息,並返回JSON格式.
def Get_Load_Info(addr):
    try:
        Head = ["HostName","Load1","Load5","Load15"]
        SysLoad = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        SysLoad.append(ret.read().split(":")[3].strip())

        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.4.1.2021.10.1.3")
        load = list(re.sub(".*STRING: ", "", ret.read()).split("\n"))
        SysLoad.append(load[0])
        SysLoad.append(load[1])
        SysLoad.append(load[2])
        return dict(zip(Head,SysLoad))
    except Exception:
        return 0

# 通過SNMP獲取系統內存占用: 內存利用率,獲取到之后,將其轉化為字典格式保存。
def Get_Mem_Info(addr):
    try:
        Head = ["HostName","memTotalSwap","memAvailSwap","memTotalReal","memTotalFree"]
        SysMem = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        SysMem.append(ret.read().split(":")[3].strip())
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.4.1.2021.4")
        mem = ret.read().split("\n")
        for i in [2,3,4,6]:
            SysMem.append(re.sub(".*INTEGER: ","",mem[i]).split(" ")[0])
        return dict(zip(Head,SysMem))
    except Exception:
        return 0

# 通過SNMP獲取系統磁盤數據: 這個案例並不完整,我只寫了一點,后面有個問題一直沒有解決.
def Get_Disk_Info(addr):
    try:
        dic = {}
        list = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageDescr")
        DiskName = ret.read().split("\n")
        ret =os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageUsed")
        DiskUsed = ret.read().split("\n")
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageSize")
        DiskSize = ret.read().split("\n")

        for i in range(1,len(DiskName) - 7):
            dic["Name"]= DiskName[i + 5].split(":")[3]
            dic["Used"]= DiskUsed[i + 5].split(":")[3]
            dic["Size"]= DiskSize[i + 5].split(":")[3]
            list.append(dic)
        return list
    except Exception:
        return 0

if __name__ == '__main__':
    for i in range(100):
        dic = Get_CPU_Info("192.168.1.20")
        print(dic)
        time.sleep(1)

通過SNMP收集主機CPU利用率 通過SNMP協議,收集目標主機的CPU利用率(百分比),並返回JSON字符串.

import os,re,time

def Get_CPU_Info(addr):
    try:
        Head = ["HostName","CoreLoad","CpuUser","CpuSystem","CpuIdle"]
        CPU = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        CPU.append(ret.read().split(":")[3].strip())
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.25.3.3.1.2")
        CPU.append(ret.read().split(":")[3].strip())

        for i in [9,10,11]:
            ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " 1.3.6.1.4.1.2021.11.{}.0".format(i))
            ret = ret.read()
            Info = ret.split(":")[3].strip()
            CPU.append(Info)
        return dict(zip(Head,CPU))
    except Exception:
        return 0

if __name__ == '__main__':
    for i in range(100):
        dic = Get_CPU_Info("192.168.1.20")
        print(dic)
        time.sleep(1)

通過SNMP獲取系統CPU負載信息 分別獲取到系統的1,5,15分鍾的負載信息,並返回JSON格式.

import os,re,time

def Get_Load_Info(addr):
    try:
        Head = ["HostName","Load1","Load5","Load15"]
        SysLoad = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        SysLoad.append(ret.read().split(":")[3].strip())

        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.4.1.2021.10.1.3")
        load = list(re.sub(".*STRING: ", "", ret.read()).split("\n"))
        SysLoad.append(load[0])
        SysLoad.append(load[1])
        SysLoad.append(load[2])
        return dict(zip(Head,SysLoad))
    except Exception:
        return 0

if __name__ == '__main__':
    dic = Get_Load_Info("192.168.1.20")
    print(dic)

通過SNMP獲取系統內存占用 內存利用率,獲取到之后,將其轉化為字典格式保存。

import os,re,time

def Get_Mem_Info(addr):
    try:
        Head = ["HostName","memTotalSwap","memAvailSwap","memTotalReal","memTotalFree"]
        SysMem = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.2.1.1.5")
        SysMem.append(ret.read().split(":")[3].strip())
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " .1.3.6.1.4.1.2021.4")
        mem = ret.read().split("\n")
        for i in [2,3,4,6]:
            SysMem.append(re.sub(".*INTEGER: ","",mem[i]).split(" ")[0])
        return dict(zip(Head,SysMem))
    except Exception:
        return 0

if __name__ == '__main__':
    dic = Get_Mem_Info("192.168.1.20")
    print(dic)

通過SNMP獲取系統磁盤數據 這個案例並不完整,我只寫了一點,后面有個問題一直沒有解決.

import os,re,time

def Get_Disk_Info(addr):
    try:
        dic = {}
        list = []
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageDescr")
        DiskName = ret.read().split("\n")
        ret =os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageUsed")
        DiskUsed = ret.read().split("\n")
        ret = os.popen("snmpwalk -v 2c -c nmap " + addr + " HOST-RESOURCES-MIB::hrStorageSize")
        DiskSize = ret.read().split("\n")

        for i in range(1,len(DiskName) - 7):
            dic["Name"]= DiskName[i + 5].split(":")[3]
            dic["Used"]= DiskUsed[i + 5].split(":")[3]
            dic["Size"]= DiskSize[i + 5].split(":")[3]
            list.append(dic)
        return list
    except Exception:
        return 0

if __name__ == '__main__':
     list = Get_Disk_Info("192.168.1.20")
     print(list)

接下來,我們使用pysnmp模塊來做,安裝pysnmp很簡單,執行命令pip install pysnmp即可,安裝后,使用以下代碼執行即可獲取到目標數據,網上的那些轉載的都是坑,沒一個能用的,這個案例是官方案例,可以使用。

from pysnmp.hlapi import *

iterator = getCmd(SnmpEngine(),
                  CommunityData('public'),
                  UdpTransportTarget(('192.168.1.113', 161)),
                  ContextData(),
                  ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))

errorIndication, errorStatus, errorIndex, varBinds = next(iterator)

if errorIndication:
    print(errorIndication)
else:
    if errorStatus:
        print('%s at %s' % (errorStatus.prettyPrint(), varBinds[int(errorIndex)-1] if errorIndex else '?'))
    else:
        for varBind in varBinds:
            print(' = '.join([x.prettyPrint() for x in varBind]))

首先我們以一個OID序號為例,我們查詢特定序號對應的名稱,然后將其記錄下來,例如下面這樣。

在客戶機上面,需要在服務列,開啟SNMP支持,並設置好一個團體名稱,如下圖。

然后我們簡單的封裝一個類,先來測試一下是否能通。

# snmpwalk -v 2c -c public 192.168.1.113 .1.3.6.1.2.1.1.5
from pysnmp.hlapi import *


class NetSNMP():
    def __init__(self,address,region):
        self.region = region
        self.address = address

    # 獲取指定數據的方法
    def GetNumber(self,oid,sub_oid,sub_id):
        iterator = getCmd(SnmpEngine(),
                          CommunityData(self.region),
                          UdpTransportTarget((self.address, 161)),
                          ContextData(),
                          ObjectType(ObjectIdentity(oid, sub_oid, sub_id)))
        errorIndication, errorStatus, errorIndex, varBinds = next(iterator)

        if errorIndication:
            return False
        else:
            if errorStatus:
                return False
            else:
                for varBind in varBinds:
                    return [x.prettyPrint() for x in varBind]

if __name__ == "__main__":

    # 初始化
    ptr = NetSNMP("192.168.1.101","public")

    # 設置OID數據集
    ret = ptr.GetNumber("HOST-RESOURCES-MIB","hrMemorySize",0)
    print("類型: {} --> 返回結果: {} --> 解析: {}".format(type(ret),ret,ret[1]))

運行后,即可讀取到內存數據,如下。


未完待續


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM