
本記事では、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 Only、privateとして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エージェントのシミュレータの作成方法について学んでいきたいと思います。