はじめに

ネットワーク管理に興味があるけど、どこから始めたらいいか分からない…そんな方に、PythonとPySNMPを使ったSNMPのガイドをご紹介!初心者にもわかりやすくSNMPの基本から解説しているので、ネットワークの監視や管理を学びたい方はぜひ気軽にチェックしてみてくださいね!
PySNMPとは何か
PySNMPは、PythonでSimple Network Management Protocol(SNMP)を扱うためのライブラリです。SNMPは、ネットワークデバイスや管理ステーション間で情報を交換し、ネットワーク管理を行うための標準プロトコルです。特に、ネットワーク機器の監視や設定、トラブルシューティングに広く使われています。
PySNMPは、このSNMPをPythonプログラムから操作できるようにするためのツールで、簡単なインターフェースと柔軟な機能を提供します。これにより、ネットワーク管理者や開発者は、複雑なネットワーク環境においても効率的に監視や管理を行うことができます。
SNMPの概要とその重要性
SNMPは1980年代後半に開発されたプロトコルで、今日でも多くの企業や組織でネットワーク管理の標準ツールとして利用されています。SNMPは、ネットワーク内のデバイス(ルーター、スイッチ、サーバーなど)から情報を収集し、これをネットワーク管理システム(NMS)に提供する役割を果たします。さらに、SNMPを使用して、これらのデバイスの設定をリモートで変更することも可能です。
SNMPは、以下のようなシナリオで特に重要です。
- ネットワークの監視:デバイスのステータス、使用率、エラーなどをリアルタイムで監視。
- 障害の検出と対応:ネットワーク上で異常が発生した際に即座に通知し、適切な対策を講じる。
- パフォーマンスの最適化:ネットワーク全体のパフォーマンスを監視し、改善点を見つけ出す。
PySNMPの役割と用途
PySNMPは、これらのSNMP操作をPythonでプログラム的に実行するための強力なツールです。具体的には、以下のような用途で使用されています。
- ネットワークモニタリングツールの開発:特定のネットワーク条件を監視し、アラートを出すカスタムツールの作成。
- 自動化スクリプトの作成:ルーターやスイッチの設定変更を自動化するスクリプトの作成。
- ネットワークテスト:SNMPを用いたネットワークの健全性チェックやベンチマークテスト。
PySNMPを使うことで、複雑なSNMPプロトコルをPythonの簡潔なコードで操作できるため、ネットワーク管理の効率が大幅に向上します。
PySNMPのインストール方法

必要な環境と依存関係
PySNMPは、Python 3.5以上のバージョンで動作するよう設計されています。そのため、まずはPythonが適切にインストールされていることを確認する必要があります。加えて、PySNMPは他のパッケージに依存しており、それらは自動的にインストールされますが、いくつかの主要な依存パッケージを知っておくとよいでしょう。
- PyCryptoDome:SNMPv3での暗号化に使用される暗号ライブラリです。
- PyASN1:ASN.1データのエンコード/デコードを行うライブラリで、SNMPメッセージの構築に使われます。
これらの依存パッケージは、PySNMPをインストールするときに一緒にインストールされますが、手動でのインストールも可能です。
PySNMPのインストール手順
PySNMPのインストールは非常に簡単で、Pythonのパッケージ管理ツールであるpipを使用します。以下のコマンドをターミナル(またはコマンドプロンプト)で実行してください。
pip install pysnmpこのコマンドを実行すると、PySNMPとその依存関係が自動的にダウンロードされ、インストールされます。インストールが完了したら、PySNMPを使用する準備が整います。
動作確認方法
インストールが正しく行われたことを確認するために、簡単なテストを行ってみましょう。以下のPythonコードを実行してみてください。これは、PySNMPの基本機能であるSNMP GETリクエストを実行するためのコードです。
from pysnmp.hlapi import *
# SNMP GET リクエストの設定
iterator = getCmd(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'))
)
# 結果を取得
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
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]))このコードは、demo.snmplabs.comという公開SNMPサーバーから、システム情報(OID: 1.3.6.1.2.1.1.1.0)を取得します。正しく動作すれば、サーバーからの応答としてシステム情報が表示されるはずです。
もしエラーが発生した場合は、エラーメッセージに従って設定を確認するか、ネットワーク接続を見直してください。
基本的な使用方法
SNMPエージェントとの接続方法
PySNMPを使用して、SNMPエージェントに接続するためには、いくつかの基本的な概念を理解する必要があります。まず、SNMPエージェントは、ネットワークデバイス(ルーター、スイッチ、サーバーなど)上で動作し、管理情報ベース(MIB)からデータを提供します。PySNMPを使ってエージェントに接続し、これらのデータを取得したり、設定を変更したりできます。
接続を行うには、以下の情報が必要です。
- エージェントのIPアドレスとポート番号:通常、SNMPはUDPポート161を使用します。
- コミュニティ名:SNMPv1およびSNMPv2cで使用されるパスワードのようなもの。デフォルトでは「public」と設定されていることが多いです。
- OID(オブジェクト識別子):取得したい情報や操作対象を指定するための識別子。
基本的なSNMP操作 (GET, SET, WALK) の解説
SNMP操作にはいくつかの基本的な種類がありますが、ここでは代表的な3つについて説明します。
SNMP GET
GETリクエストは、エージェントから特定のOIDの値を取得するために使用します。例えば、デバイスのシステム情報やインターフェースのステータスを取得する際に使います。
from pysnmp.hlapi import *
iterator = getCmd(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'))
)
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
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]))SNMP SET
SETリクエストは、エージェントのOIDに対応する値を変更するために使用します。ネットワーク機器の設定変更などに利用されます。
iterator = setCmd(
SnmpEngine(),
CommunityData('private', mpModel=0), # 'private'コミュニティは通常、書き込み可能です
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.5.0'), 'New System Name')
)
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
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]))SNMP WALK
WALKリクエストは、特定のOIDから始まり、そのツリーにあるすべてのOIDを順に取得します。ネットワーク機器全体の情報を一括で取得する際に便利です。
from pysnmp.hlapi import *
iterator = nextCmd(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.2.2.1')),
lexicographicMode=False
)
for errorIndication, errorStatus, errorIndex, varBinds in iterator:
if errorIndication:
print(errorIndication)
break
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
break
else:
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))コード例: SNMP GETリクエストの実装
上記で紹介したgetCmdの例をもう一度確認します。このコードは、特定のOIDに対するSNMP GETリクエストを実行し、結果を取得する基本的なものです。
from pysnmp.hlapi import *
iterator = getCmd(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'))
)
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
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]))このコードを実行することで、指定したSNMPエージェントに対してGETリクエストが送信され、結果が表示されます。このように、PySNMPを使うと簡単にSNMP操作を行うことができ、ネットワーク管理タスクを自動化するためのスクリプトを簡単に作成できます。
高度な機能

SNMPトラップの受信と処理
SNMPトラップは、ネットワークデバイスが自発的に管理ステーションに対して通知を送るメカニズムです。これにより、障害やイベントが発生した際に即座に対応することができます。PySNMPを使用すると、このトラップを受信して処理することが可能です。
以下は、SNMPトラップを受信するための基本的なコード例です。
from pysnmp.hlapi.asyncore import *
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
varBinds, cbCtx):
print('トラップ受信:')
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
snmpEngine = SnmpEngine()
snmpEngine.transportDispatcher.jobStarted(1) # 受信待ち状態
# SNMPトラップリスナーの設定
config.addTransport(
snmpEngine,
udp.domainName,
udp.UdpTransport().openServerMode(('localhost', 162))
)
# コミュニティ名を設定(SNMPv2c)
config.addV1System(snmpEngine, 'my-area', 'public')
# SNMPエージェントからのトラップを処理
ntfrcv.NotificationReceiver(snmpEngine, cbFun)
try:
snmpEngine.transportDispatcher.runDispatcher()
except:
snmpEngine.transportDispatcher.closeDispatcher()
raiseこのコードでは、localhostで162番ポートをリッスンして、SNMPトラップを受信します。トラップが受信されると、cbFunというコールバック関数が呼ばれ、トラップの内容が出力されます。
トラップリスナーを設定する際には、SNMPエージェントが送信するトラップのコミュニティ名やセキュリティ設定が正しいことを確認する必要があります。
非同期操作の実装方法
PySNMPでは、非同期操作をサポートしており、大量のSNMPリクエストを効率的に処理することが可能です。これにより、ネットワーク全体の情報を短時間で取得したり、同時に複数のエージェントにリクエストを送信したりすることができます。
以下に、非同期でSNMP GETリクエストを実行する例を示します。
from pysnmp.hlapi.asyncore import *
def cbFun(sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx):
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]))
snmpEngine = SnmpEngine()
# 非同期GETリクエストの送信
getCmd(snmpEngine,
CommunityData('public', mpModel=0),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0')),
cbFun=cbFun)
snmpEngine.transportDispatcher.runDispatcher()このコードでは、GETリクエストを非同期で送信し、応答を受け取った際にcbFunが呼び出されます。非同期操作を使用することで、リクエストが完了するのを待たずに他の処理を進めることができます。
セキュリティ設定 (SNMPv3の使用)
SNMPv1やSNMPv2cでは、コミュニティ名を使ってアクセス制御を行いますが、これらのバージョンには暗号化や強力な認証機能がありません。一方、SNMPv3はセキュリティを重視しており、メッセージの暗号化や認証機能をサポートしています。
以下は、SNMPv3を使用してGETリクエストを送信するコード例です。
from pysnmp.hlapi import *
iterator = getCmd(
SnmpEngine(),
UsmUserData('usr-md5-des', 'authkey1', 'privkey1',
authProtocol=usmHMACMD5AuthProtocol,
privProtocol=usmDESPrivProtocol),
UdpTransportTarget(('demo.snmplabs.com', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'))
)
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
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]))この例では、UsmUserDataを使用して、ユーザー名、認証キー、暗号化キーを指定しています。SNMPv3は、セキュアな通信が求められる環境で特に有用です。
よくある問題とその対処法
よくあるエラーメッセージとその解決策
PySNMPを使用する際に遭遇する可能性のある一般的なエラーメッセージについて、いくつか例を挙げ、それぞれの解決策を説明します。
Error: No SNMP response received before timeout
原因: このエラーメッセージは、指定したSNMPエージェントからの応答がタイムアウトした場合に表示されます。ネットワークの問題、エージェントがダウンしている、または間違ったIPアドレスやポート番号を指定していることが原因となります。
対策: エージェントのIPアドレスとポートが正しいか、エージェントが稼働しているかを確認してください。また、ネットワークの接続状況やファイアウォール設定も確認が必要です。
Error: AuthorizationError: unauthorized access
原因: SNMPコミュニティ名(SNMPv1/SNMPv2cの場合)またはユーザー情報(SNMPv3の場合)が正しく設定されていないときに発生します。アクセス権限がないため、エージェントはリクエストを拒否します。
対策: 使用しているコミュニティ名またはSNMPv3のユーザー名と認証情報が正しいか確認してください。必要に応じて、エージェント側の設定を確認し、適切なアクセス権を持つように設定します。
Error: ValueError: Malformed OID
原因: OIDが正しくない形式で指定された場合に発生するエラーです。たとえば、間違ったシンタックスや無効なOIDを指定した場合にこのエラーが表示されます。
対策: OIDが正しく指定されているか確認してください。MIBブラウザやSNMPツールを使って、OIDが正しいか検証するのも良いでしょう。
Error: End of MIB
原因: SNMP WALK操作を行ったときに、MIBツリーの最後に達すると発生するエラーメッセージです。このメッセージ自体はエラーではなく、通常の操作の一部です。
対策: 特に対策は必要ありません。MIBツリーの終端に到達したことを示すため、通常は無視しても問題ありません。
デバッグ方法
PySNMPで発生する問題をデバッグするためのいくつかのテクニックを紹介します。
デバッグロギングの有効化
PySNMPには、詳細なロギング機能が備わっており、これを有効にすることで問題の原因を特定しやすくなります。ロギングを有効にするには、以下のコードを使用します。
import logging
logging.basicConfig(level=logging.DEBUG)これにより、SNMPメッセージの送受信や内部処理の詳細なログが出力されます。問題の原因を追跡する際に非常に有用です。
Wiresharkを使用したパケットキャプチャ
Wiresharkなどのネットワークプロトコルアナライザを使用して、SNMPメッセージのパケットをキャプチャし、詳細を確認することができます。これにより、メッセージの内容やネットワークの問題を確認できます。
MIBファイルの検証
正確なOIDを使用しているかを確認するために、MIBファイルを使用してOIDを検証することが重要です。正しいMIBファイルを使用して、OIDを照合し、エラーの原因を特定します。
パフォーマンスの最適化
PySNMPのパフォーマンスを最大限に引き出すためのいくつかのポイントを紹介します。
バッチ処理の使用
複数のGETリクエストを同時に送信する場合、一度に多くのOIDをバッチで取得することで、ネットワークトラフィックを減らし、全体のパフォーマンスを向上させることができます。
非同期操作の利用
非同期操作を使用することで、同時に多数のリクエストを処理でき、待ち時間を減らしてパフォーマンスを向上させることが可能です。これは特に、大規模なネットワーク環境で有効です。
トランスポート設定の調整
UdpTransportTargetのパラメータ(例えばタイムアウトや再試行回数)を調整することで、ネットワークの状況に応じた最適な設定が可能です。
UdpTransportTarget(('demo.snmplabs.com', 161), timeout=2, retries=1)これにより、特定のネットワーク環境に最適化されたパフォーマンスを引き出すことができます。
結論
PySNMPの利点と制限
PySNMPは、Pythonを使用してSNMPプロトコルを簡単に操作するための強力なライブラリです。その利点と制限についてまとめます。
利点:
- 柔軟性と拡張性
PySNMPは、SNMPv1、v2c、v3をサポートし、さまざまなセキュリティ要件に対応できます。また、同期・非同期の操作をサポートしているため、幅広いユースケースに対応可能です。 - シンプルなインターフェース
Pythonの簡潔な構文と組み合わせることで、複雑なSNMP操作を簡単に記述できます。特に、ネットワーク監視や管理スクリプトを作成する際に非常に便利です。 - 豊富な機能
基本的なGET/SET操作に加え、WALKやトラップの受信など、SNMPの主要機能を網羅しています。
制限:
- パフォーマンス
PySNMPは、純粋なPythonで実装されているため、C言語ベースのライブラリに比べるとパフォーマンス面で劣ることがあります。大規模なネットワークでの大量のリクエスト処理には、性能がボトルネックになることがあるため、用途に応じた最適化が必要です。 - ドキュメントの限界
公式ドキュメントは充実していますが、SNMP自体の複雑さからくる学習曲線があります。SNMPの基本的な理解が必要であり、初心者には敷居が高いかもしれません。
他のSNMPライブラリとの比較
PySNMPは多機能かつ柔軟なライブラリですが、他にもPythonで利用できるSNMPライブラリがあります。代表的なものとしては、以下のものが挙げられます。
- Net-SNMP: C言語で書かれたライブラリですが、Pythonバインディングを通じて使用することが可能です。PySNMPよりもパフォーマンスが高く、大規模なネットワーク管理に適しています。ただし、セットアップがやや複雑です。
- Easy SNMP: Net-SNMPを基盤とした軽量なPythonラッパーで、シンプルで使いやすいですが、PySNMPほどの機能はありません。
これらのライブラリと比べると、PySNMPは柔軟性と機能のバランスが取れており、特にPythonベースでの開発に慣れているユーザーにとっては使いやすい選択肢となります。
今後の学習リソース
PySNMPをさらに活用するために、以下のリソースが役立ちます。
- 公式ドキュメント
PySNMPの公式ドキュメントは、基本的な使い方から高度なトピックまでをカバーしています。各機能の詳細な説明やサンプルコードが含まれており、非常に参考になります。 - SNMPの理解を深める
SNMP自体の理解を深めるために、関連書籍やオンラインチュートリアルを活用すると良いでしょう。SNMPの構造やMIBの仕組みを理解することで、PySNMPの活用範囲が広がります。 - GitHubのサンプルコード
GitHubには、PySNMPを利用したプロジェクトやスクリプトが多数公開されています。これらを参考にすることで、実際のユースケースに即した活用方法を学ぶことができます。 - オンラインコミュニティ
Stack OverflowやRedditのPythonやネットワーク管理に関するフォーラムで質問したり、議論に参加したりすることで、実践的な知識を得ることができます。

ここまで読んでいただきありがとうございます!
UdemyのPythonコースにはオンラインで学習ができる動画コンテンツがたくさんあります。
当ブログのような文章メインの説明では足りない箇所を補えると思うので、もっと詳しく勉強したいという方はぜひチェックしてみてください!


コメント