実践ネット自動化スクリプト集

実践Python:ネットワーク機器SNMPデータ収集と分析自動化

Tags: Python, ネットワーク自動化, SNMP, データ収集, 監視, pysnmp

はじめに:Pythonでネットワーク機器のSNMPデータを活用する

システムエンジニアやインフラエンジニアとして、Pythonを用いたインフラ自動化に取り組まれている方も多いことと思います。アプリケーション開発やクラウドインフラの自動化は得意とされている一方で、ネットワーク機器の直接的な操作や、SNMPといったプロトコルについては、まだ馴染みが薄いと感じているかもしれません。

しかし、ネットワーク機器から得られるSNMPデータは、機器のパフォーマンス監視、リソース利用率の把握、障害の早期検知など、システムの安定稼働に不可欠な情報源となります。これらのデータを自動的に収集し、分析・活用することは、運用効率の向上や、プロアクティブな障害対応につながります。

この記事では、Pythonのライブラリを使用してネットワーク機器のSNMPデータを収集し、さらに一歩進んで、収集したデータを自動的に分析・活用するための具体的な手法とスクリプト例をご紹介します。ネットワーク機器に関する深い知識がなくても、Pythonスキルを活かしてネットワーク監視・分析を自動化する方法を習得いただけます。

SNMPとは何か?基本を押さえる

SNMP(Simple Network Management Protocol)は、ネットワーク上の機器(ルーター、スイッチ、サーバーなど)の情報を収集し、管理するための標準的なプロトコルです。SNMPでは、主に以下の要素が登場します。

PythonからSNMPを利用する場合、Pythonスクリプトがマネージャーとなり、ネットワーク機器上のエージェントからMIBに定義された情報をOID指定で取得(GET/GETNEXT/WALK操作)するのが一般的です。

PythonでSNMPデータを収集する主要ライブラリ

PythonでSNMPを扱うためのライブラリはいくつか存在しますが、特によく使われるものに pysnmp があります。pysnmp はPythonで書かれており、SNMPv1, v2c, v3に対応し、マネージャーとしてもエージェントとしても機能できる高機能なライブラリです。

この記事では、pysnmp を使用したデータ収集に焦点を当てます。

まず、pysnmp ライブラリをインストールします。

pip install pysnmp

pysnmpを使ったSNMPデータ収集スクリプト例

ここでは、pysnmp を用いてネットワーク機器から特定のOIDの情報を取得する基本的なスクリプト例を示します。

例1:単一のOIDを取得する(GET操作)

ネットワーク機器の特定のOID(例: 1.3.6.1.2.1.1.5.0 は通常sysName、機器名を指す)を取得するスクリプトです。

from pysnmp.entity.rfc3413.oneliner import cmdrsp, context
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp

# SNMPv2c Manager設定
snmpEngine = engine.SnmpEngine()

# 対象機器と認証情報
device_ip = 'YOUR_DEVICE_IP'  # ネットワーク機器のIPアドレスに置き換えてください
community_string = 'YOUR_COMMUNITY_STRING' # SNMP Community文字列に置き換えてください
port = 161 # SNMPの標準ポート

# SNMPv2c Community-based security name: 'my-area'
# tag: 'my-v2c-tag'
config.addV2cCommunity(
    snmpEngine,
    'my-area', # securityName
    community_string # communityName
)

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode()
)

# Remote SNMP agent IPv4/UDP
config.addTransport(
    snmpEngine,
    udp.domainName + (1,), # Endpoint name
    udp.UdpTransport().openClientMode()
)

# GET操作の実行
# OIDを指定します (例: sysName)
oid_to_get = '1.3.6.1.2.1.1.5.0'

errorIndication, errorStatus, errorIndex, varBinds = cmdrsp.getCmd(
    snmpEngine,
    'my-area', # securityName
    context.ContextData(), # contextName
    udp.domainName + (1,), # transportTag
    (oid_to_get,) # OID(s) to GET
)

# 結果の表示
if errorIndication:
    print(f"SNMP Error: {errorIndication}")
elif errorStatus:
    print(f"SNMP Error: {errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex) - 1][0].prettyPrint() or '?'}")
else:
    for oid, val in varBinds:
        print(f"OID: {oid.prettyPrint()}, Value: {val.prettyPrint()}")

スクリプトの解説:

例2:複数のOIDを取得する(BULKGET操作)

複数のOIDを効率的に取得したい場合は、GETNEXTやGETBULK操作が有効です。ここでは、GETBULKに相当する操作の基本的な考え方を示します(pysnmp では bulkCmd を使用します)。

from pysnmp.entity.rfc3413.oneliner import cmdrsp, context
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp

# SNMPv2c Manager設定
snmpEngine = engine.SnmpEngine()

# 対象機器と認証情報
device_ip = 'YOUR_DEVICE_IP'
community_string = 'YOUR_COMMUNITY_STRING'
port = 161

# SNMPv2c Community-based security name: 'my-area'
# tag: 'my-v2c-tag'
config.addV2cCommunity(
    snmpEngine,
    'my-area', # securityName
    community_string # communityName
)

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode()
)

# Remote SNMP agent IPv4/UDP
config.addTransport(
    snmpEngine,
    udp.domainName + (1,), # Endpoint name
    udp.UdpTransport().openClientMode()
)

# BULKGET操作の実行 (例: sysDescrとsysUpTimeを取得)
# nonRepeaters=0: 最初のOIDは繰り返し取得しない (通常0か1)
# maxRepetitions=10: 後続のOIDリストの各エントリに対して最大何回繰り返すか
oids_to_get = ['1.3.6.1.2.1.1.1.0', '1.3.6.1.2.1.1.3.0'] # 例: sysDescr, sysUpTime

errorIndication, errorStatus, errorIndex, varBinds = cmdrsp.bulkCmd(
    snmpEngine,
    'my-area', # securityName
    context.ContextData(), # contextName
    udp.domainName + (1,), # transportTag
    0, # nonRepeaters
    50, # maxRepetitions (一度に取得する最大項目数)
    *(oids_to_get) # OID(s) to GETBULK
)

# 結果の表示
if errorIndication:
    print(f"SNMP Error: {errorIndication}")
elif errorStatus:
    print(f"SNMP Error: {errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex) - 1][0].prettyPrint() or '?'}")
else:
    for row in varBinds:
        for oid, val in row:
             print(f"OID: {oid.prettyPrint()}, Value: {val.prettyPrint()}")

補足:

収集データの分析・活用例

SNMPで取得した生データ(OIDと値のペア)だけでは、その意味を理解したり、傾向を把握したりするのは困難です。Pythonを使って、これらのデータを現場で役立つ形に加工・分析・活用する例をいくつかご紹介します。

1. 閾値監視と通知

特定のOIDの値が、あらかじめ定義した閾値を超えた場合に、何らかのアクション(例: ログ出力、Slack通知、メール送信など)を実行します。

# 例: CPU使用率 (OIDはベンダーや機種により異なる場合があります)
# ここでは仮のOIDを使用します。実際の機器のMIBを確認してください。
cpu_usage_oid = '1.3.6.1.4.1.9.2.1.58.0' # Ciscoなどの例(実際には異なる可能性あり)
threshold_percent = 80 # 閾値: 80%

# 上記のgetCmdスクリプトで cpu_usage_oid の値を取得する処理を記述
# 例として、取得した値が cpu_value という変数に入ったと仮定します

try:
    cpu_value = int(cpu_value) # 取得した値が文字列の場合、整数に変換
    if cpu_value > threshold_percent:
        print(f"ALERT: CPU使用率が閾値を超えました - {cpu_value}%")
        # ここに通知処理を追加 (例: Slack Webhookを呼び出す)
        # import requests
        # requests.post('YOUR_SLACK_WEBHOOK_URL', json={'text': f'ALERT: {device_ip} CPU usage is {cpu_value}%'})
except ValueError:
    print(f"WARN: CPU使用率の値'{cpu_value}'が数値ではありませんでした。")
except Exception as e:
    print(f"ERROR: 閾値チェック中にエラーが発生しました - {e}")

2. 時系列データとしての保存と簡易レポート

収集したSNMPデータを定期的に取得し、CSVファイルやデータベースに保存することで、時系列データとして蓄積できます。これにより、過去の推移を追跡したり、簡易的なレポートを生成したりすることが可能になります。

import csv
import datetime
import os

# 例: インターフェースの送受信バイト数カウンター (OIDはベンダーや機種により異なる)
# ifInOctets, ifOutOctets のテーブルOID
interface_mib_table_oid = '1.3.6.1.2.1.2.2.1'

# 収集したデータを保存するCSVファイル
csv_file = 'snmp_data.csv'

def append_data_to_csv(data, filename):
    """収集したデータをCSVファイルに追記する"""
    file_exists = os.path.exists(filename)
    with open(filename, 'a', newline='') as f:
        writer = csv.writer(f)
        if not file_exists:
            # ヘッダー行を書き込む (OIDをヘッダーとする)
            header = ['timestamp'] + [str(oid) for oid, _ in data]
            writer.writerow(header)
        # データ行を書き込む
        row = [datetime.datetime.now().isoformat()] + [str(val) for _, val in data]
        writer.writerow(row)

# --- データ収集処理(上記bulkCmdなどを利用) ---
# 複数のOID/テーブルからデータを取得し、varBinds に格納したと仮定
# 取得した varBinds (list of list of (oid, val)) をフラットなリスト of (oid, val) に変換する例
flat_data = [(oid, val) for row in varBinds for oid, val in row]
# --- データ収集処理 終了 ---

# 収集データをCSVに保存
append_data_to_csv(flat_data, csv_file)

print(f"SNMPデータを'{csv_file}'に追記しました。")

# 簡易レポート例: CSVからデータを読み込み、最新の値を取得
if os.path.exists(csv_file):
    with open(csv_file, 'r') as f:
        reader = csv.reader(f)
        header = next(reader) # ヘッダー行をスキップ
        last_row = None
        for row in reader:
            last_row = row # 最後の行を保持

        if last_row:
            print("\n--- 最新のデータ ---")
            timestamp = last_row[0]
            print(f"タイムスタンプ: {timestamp}")
            for i in range(1, len(last_row)):
                print(f"{header[i]}: {last_row[i]}")

これは非常に簡易的な例ですが、pandas ライブラリなどを使用すれば、より高度なデータ分析(平均値、最大値、変動の算出など)や、matplotlibなどによるグラフ化も容易に行えます。

実践的な考慮事項

現場でこれらのスクリプトを運用する際には、いくつかの考慮事項があります。

他の自動化ツール/IaCとの連携

PythonによるSNMPデータ収集自動化は、インフラ自動化全体のワークフローの中に組み込むことで、より大きな価値を発揮します。

まとめ

この記事では、Pythonとpysnmpライブラリを用いたネットワーク機器のSNMPデータ収集および分析自動化の基本的な手法をご紹介しました。ネットワーク機器の操作に不慣れな方でも、Pythonスキルを活かせば、機器の内部状態に関する重要な情報を効率的に取得し、活用できるようになります。

ご紹介したスクリプト例はあくまで出発点です。これを基に、エラーハンドリングの強化、認証情報のセキュアな管理、並列処理の実装、収集データの長期保存と高度な分析、そして他の運用ツールとの連携を進めることで、より実践的で信頼性の高いネットワーク監視・分析自動化システムを構築することが可能です。

ネットワーク自動化の領域は広く、CLI、API、SNMPなど様々なアプローチがあります。SNMPは機器の状態監視において非常に強力な手段の一つであり、Pythonによる自動化は、その活用を大きく加速させます。ぜひこの記事で得た知識を、日々の運用業務の効率化に役立ててください。