Windows + Python3 + PySNMPで、SNMPのGET Requestを送信する

Windows + Python3でSNMPを扱おうとしたところ、PySNMPが動きそうでした。

そこで、公式ドキュメントや書籍を見て手を動かした時のメモを残します。

なお、SNMPデータの取得元として、今回は昔使ったプリンタPX-105のインク本数を取得してみました。
Ruby + Sinatra + SNMPでPX-105のインク残量を取得・表示する - メモ的な思考的な

 

環境

  • Windows10 x64
  • Python 3.5.1 32bit
  • PySNMP 4.3.2

なお、PySNMPはPyCryptoに依存しています。

そのため、WindowsのPython3.5の環境にインストールするにはVisual Studio 2015、または、Visual C++ Build Tools 2015を事前にインストールしておきます。
Pythonの拡張モジュールインストール時にvcvarsall.batエラーが出たため、Visual C++ Build Tools 2015でビルドした - メモ的な思考的な

 

D:\Sandbox\pysnmp_sample>virtualenv -p c:\python35-32\python.exe env
D:\Sandbox\pysnmp_sample>env\Scripts\activate

(env) D:\Sandbox\pysnmp_sample>pip install pysnmp

(env) D:\Sandbox\pysnmp_sample>pip list
pip (8.1.2)
ply (3.8)
pyasn1 (0.1.9)
pycrypto (2.6.1)
pysmi (0.0.7)
pysnmp (4.3.2)
setuptools (22.0.5)
wheel (0.29.0)

 

GET requestの送信

PySNMPのドキュメントを読んだところ、実装方法として、

の2つがありました。

どちらを試そうかと考えましたが、ドキュメントには

Unless you have a vary specific task, one of high-level APIs might solve your SNMP needs.

と書かれていたため、今回はHigh-level SNMPだけ試してみます。

ドキュメントによると、基本的な流れは、

  • pysnmp.hlapi.getCmd()でコマンドを作成
  • 作ったコマンドをnext()で実行

のようでした。

 
pysnmp.hlapi.getCmd()ではいくつか引数がありました。
GET command — PySNMP

今回設定した内容は

でした。

実装と実行結果は以下の通りです。

import pysnmp.hlapi
OID_MARKER_PROCESS_COLORANTS = "1.3.6.1.2.1.43.10.2.1.6.1.1"

g = pysnmp.hlapi.getCmd(
    pysnmp.hlapi.SnmpEngine(),
    pysnmp.hlapi.CommunityData(SNMP_COMMUNITY, mpModel=0),
    pysnmp.hlapi.UdpTransportTarget((IP, PORT)),
    pysnmp.hlapi.ContextData(),
    pysnmp.hlapi.ObjectType(pysnmp.hlapi.ObjectIdentity(OID_MARKER_PROCESS_COLORANTS))
)
    
errIndication, errorStatus, errorIndex, varBinds = next(g)

print(varBinds)
# => [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.43.10.2.1.6.1.1')), Integer32(4))]

 
また、ドキュメントには書かれていないものの、この本に書かれていたものも試してみます。
Pro Python System Administration - Apress IT eBooks & Books

from pysnmp.entity.rfc3413.oneliner import cmdgen
OID_MARKER_PROCESS_COLORANTS = "1.3.6.1.2.1.43.10.2.1.6.1.1"

cg = cmdgen.CommandGenerator()
errIndication, errorStatus, errorIndex, varBinds = cg.getCmd(
    cmdgen.CommunityData('my-manager', SNMP_COMMUNITY, mpModel=0),
    cmdgen.UdpTransportTarget((IP, PORT)),
    OID_MARKER_PROCESS_COLORANTS
)

print(varBinds)
# => [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.43.10.2.1.6.1.1')), Integer32(4))]

同じように動作しました。

 
前者と後者、どちらを使うのが良いのか分からなかったため、PySNMPのソースコードを読んでみました。ただ、いくつも同じようなファイルやソースコードが並んでいて読み解くのが難しかったこともあり、諦めました。

ドキュメントに記載されている分、前者のほうが良いのでしょうか。

 

ソースコード

GitHubに上げました。
thinkAmi-sandbox/PySNMP-sample

 

Windowsでは扱えないもの

PySNMP以外にもPythonライブラリはありましたが、いずれもWindowsで使うのは難しそうでした。

 

Snimpy

SNMPを扱うためにPySNMPを使っているものの、PyPIにOSとしてPOSIXが必要そうだったため、諦めました。

 

easysnmp

NET-SNMPがベースなため、Windowsでは厳しそうです。