Engineering Note

プログラミングなどの技術的なメモ

PythonのPySNMPの基本的な使い方

network_icon

本記事では、PythonのPySNMPライブラリを使用して、SNMPに対応したIP機器などに要求するSNMPコマンドの基本的な使い方について学んでいきます。

 

 

SNMPとは

SNMP(Simple Network Management Protocol)とは、IP機器(サーバやルータなど)を管理するために1988年に導入されたプロトコルです。

SNMPを用いることで、サーバなどのCPUの使用率や温度状態をポーリングしたり、またルータなどのインタフェースダウンなど異常が発生した際にトラップ(Trap)と呼ばれるものを管理者(Manager)に送信することで、障害検知を容易にすることができます。

SNMPはこれまでにSNMPv1、SNMPv2(厳密にはSNMPv2c)、SNMPv3の3つのバージョンがありますが、SNMPv2がデファクトスタンダードとなっています。

 

PySNMPのインストール

PySNMPは以下のSNMP Labsというところがリリースしているライブラリになります。

 

 

以下はDocumentationになります。

 

 

それでは、pipからPySNMPをインストールします。

なお、Pythonのバージョンは3.6.8になります。

 

 > pip3 install pysnmp
 > pip3 list | grep pysnmp
 pysnmp (4.4.12)

 

上記バージョンのPySNMPがインストールされました。

 

Ciscoルータの設定

GNS3上で起動したCiscoルータ(c7200)に以下のsnmp設定を行います

ここではpublicとしてRead OnlyprivateとしてRead Writeを設定します。

 

 Router(config)# snmp-server community public RO
 Router(config)# snmp-server community private RW

 

snmpwalkコマンド

snmpwalkコマンドとは、機器が保有するMIBツリーの一部を読み込むためのコマンドで、実際はget-nextの操作を行うものになります。

以下ではインタフェース情報を取得しています。

 

# snmpwalk.py
from pysnmp.hlapi import *
import sys

if len(sys.argv) != 4:
    print("Usage: {} modName symName HOSTNAME".format(sys.argv[0]))
    sys.exit(1)

modName = sys.argv[1]
symName = sys.argv[2]
router_ip = sys.argv[3]

g = nextCmd(SnmpEngine(),
           CommunityData('public'),
           UdpTransportTarget((router_ip, 161)),
           ContextData(),
           ObjectType(ObjectIdentity(modName, symName)),
           lexicographicMode=False)

while True:
    try:
        errorIndication, errorStatus, errorIndex, varBinds = next(g)
        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]))
    except StopIteration:
        break

 

上記snmpwalkのPythonスクリプトを実行してみます。

 

 > python3 snmpwalk.py IF-MIB interfaces router_ip
 IF-MIB::ifNumber.0 = 3
 IF-MIB::ifIndex.1 = 1
 IF-MIB::ifIndex.2 = 2
 IF-MIB::ifIndex.4 = 4
 IF-MIB::ifDescr.1 = FastEthernet0/0
 IF-MIB::ifDescr.2 = FastEthernet0/1
 IF-MIB::ifDescr.4 = Null0
 IF-MIB::ifType.1 = ethernetCsmacd
 IF-MIB::ifType.2 = ethernetCsmacd
 IF-MIB::ifType.4 = other
 IF-MIB::ifMtu.1 = 1500
 IF-MIB::ifMtu.2 = 1500
 IF-MIB::ifMtu.4 = 1500
 IF-MIB::ifSpeed.1 = 100000000
 IF-MIB::ifSpeed.2 = 100000000
 IF-MIB::ifSpeed.4 = 4294967295
 IF-MIB::ifPhysAddress.1 = ca:01:17:4c:00:08
 IF-MIB::ifPhysAddress.2 = ca:01:17:4c:00:06
 IF-MIB::ifPhysAddress.4 = 
 IF-MIB::ifAdminStatus.1 = up
 IF-MIB::ifAdminStatus.2 = down
 IF-MIB::ifAdminStatus.4 = up
 IF-MIB::ifOperStatus.1 = up
 IF-MIB::ifOperStatus.2 = down
 IF-MIB::ifOperStatus.4 = up
 .
 .
 .

 

上記でinterfacesに関するMIB(IF-MIB)が取得できました。

 

snmpgetコマンド

snmpgetコマンドとは、1度に一つのMIBオブジェクトを取得するコマンドになります。

以下ではインタフェース(FastEthernet0/1)の状態を取得しています。

なお、ifOperStatusは"The current operational state of the interface"の意味になります。

 

# snmpget.py
from pysnmp.hlapi import *
import sys

if len(sys.argv) != 4:
    print("Usage: {} modName symName HOSTNAME".format(sys.argv[0]))
    sys.exit(1)

modName = sys.argv[1]
if "." in sys.argv[2]:
    symName, value = sys.argv[2].split('.')
else:
    symName = sys.argv[2]
    value = 0
router_ip = sys.argv[3]

errorIndication, errorStatus, errorIndex, varBinds = next(
    getCmd(SnmpEngine(),
    CommunityData('public'),
    UdpTransportTarget((router_ip, 161)),
    ContextData(),
    ObjectType(ObjectIdentity(modName, symName, value)))
)

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]))

 

上記snmpgetのPythonスクリプトを実行してみます。

 

 > python3 snmpget.py IF-MIB ifOperStatus.2 router_ip
 IF-MIB::ifOperStatus.2 = down

 

ポートがshutdown状態であることがわかりました。

 

snmpsetコマンド

snmpsetコマンドとは、対象のオブジェクトの状態を変更する時に用い、コミュニティがread-writeまたはwrite-onlyになっている場合可能になります。

以下では上記で確認したFastEthernet0/1のインタフェースをupにしてみます。

インタフェースの状態を変更するにはifAdminStatusを指定し、Integerを意味するiの引数の後に変更する値を指定します。

 

# snmpset.py
from pysnmp.hlapi import *
import sys

if len(sys.argv) != 6:
    print("Usage: {} modName symName TYPE VALUE HOSTNAME".format(sys.argv[0]))
    sys.exit(1)

modName = sys.argv[1]
if "." in sys.argv[2]:
    symName, value = sys.argv[2].split('.')
else:
    symName = sys.argv[2]
    value = 0
set_value = sys.argv[4]
router_ip = sys.argv[5]

if sys.argv[3] == 'i':
    set_value = int(set_value)

errorIndication, errorStatus, errorIndex, varBinds = next(
    setCmd(SnmpEngine(),
    CommunityData('private'),
    UdpTransportTarget((router_ip, 161)),
    ContextData(),
    ObjectType(ObjectIdentity(modName, symName, value), set_value))
)

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]))

 

上記snmpsetのPythonスクリプトを実行してみます。

 

 > python3 snmpset.py IF-MIB ifAdminStatus.2 i 1 router_ip
 IF-MIB::ifAdminStatus.2 = up

 

インタフェースがno shutdwonになったことが確認できます。

 

最後に

今回はPythonのPySNMPライブラリを用いて簡単なSNMPコマンドの実行方法について学びました。

次回はSNMPエージェントのシミュレータの作成方法について学んでいきたいと思います。

  

参考書籍

入門SNMP