Pythonによるネットワーク構成図自動生成:データ収集から可視化まで
システムやインフラの全体像を把握する上で、ネットワーク構成図は非常に重要なドキュメントです。しかし、機器構成の変更や拡張が頻繁に行われる現場では、構成図を手動で最新の状態に保つことは容易ではありません。特に、ネットワーク機器の操作や構成情報にあまり慣れていない場合、現状把握に時間がかかり、自動化を進める上での障壁となることもあります。
この記事では、Pythonのスキルを活かして、ネットワーク機器から情報を収集し、構成図を自動生成する手法について解説します。これにより、常に最新のネットワーク構成を視覚的に把握できるようになり、インフラ運用や自動化の効率化に貢献できます。
ネットワーク構成図自動生成のステップ
ネットワーク構成図を自動生成するためには、主に以下のステップが必要となります。
- 情報の収集: ネットワーク機器から構成図作成に必要な情報を収集します。
- データ整形: 収集した生データを、図の描画に適した構造化されたデータに整形します。
- 関係性の特定: 機器間の接続関係などの論理的な関係性を特定します。
- 構成図の描画: 整形・特定した情報をもとに構成図を描画します。
これらのステップをPythonを使って自動化する方法を見ていきましょう。
1. 情報の収集
構成図を描くためには、最低限以下の情報が必要になります。
- 機器リスト: ネットワーク内のルーター、スイッチ、ファイアウォールなどの機器一覧。
- インターフェース情報: 各機器のインターフェース名、IPアドレス、ステータスなど。
- 接続情報: どの機器のどのインターフェースが、別のどの機器のどのインターフェースに接続されているか。
これらの情報を収集するための一般的な方法としては、以下のものが挙げられます。
- CLIコマンド実行: NetmikoやParamikoを使って、ネットワーク機器にログインし、
show ip interface brief
やshow lldp neighbor
(Cisco系の場合、show cdp neighbor
) などのコマンドを実行し、その出力をパースします。 - SNMP: SNMPエージェントが有効になっている機器から、MIB情報をクエリして機器情報やインターフェース情報を取得します。
- ネットワーク機器API: RESTConfやNETConfなどのAPIが利用可能な機器であれば、これらを使って構造化されたデータを直接取得できます。
ここでは、Pythonを使ったCLIコマンド実行による情報収集に焦点を当てます。特に、機器間の接続情報を得るには、LLDP (Link Layer Discovery Protocol) や CDP (Cisco Discovery Protocol) のネイバー情報が非常に有用です。これらのプロトコルは、隣接する機器の情報を相互に通知するため、構成図における「エッジ」(接続線)の情報を自動的に収集するのに役立ちます。
例として、Netmikoを使ってCisco機器からLLDPネイバー情報を取得するコードの断片を示します。
from netmiko import ConnectHandler
import yaml # 例として認証情報はyamlファイルから読み込む場合
# 接続情報 (例)
device = {
'device_type': 'cisco_ios',
'host': 'your_device_ip',
'username': 'your_username',
'password': 'your_password',
# 必要に応じて port, secret なども追加
}
try:
# NetmikoでSSH接続を確立
with ConnectHandler(**device) as net_connect:
# LLDPネイバー情報を取得するコマンドを実行
# ベンダーやOSによってコマンドは異なります。
output = net_connect.send_command("show lldp neighbor detail")
print("--- LLDP Neighbor Info ---")
print(output)
print("------------------------")
# ここで取得したoutputを後続の処理でパースします。
except Exception as e:
print(f"Error connecting to device or executing command: {e}")
この output
には、隣接する機器名、その機器のポート、自機器のポートなどが含まれています。このテキストデータをパースして、図の描画に適したデータ構造に変換する必要があります。
2. データ整形と関係性の特定
収集したLLDP/CDPの出力はテキスト形式です。構成図を描画するためには、「ノード」(機器)と「エッジ」(接続)の関係性を明確にした構造化データが必要です。テキスト出力をパースして、以下のような形式のデータを生成します。
- ノードリスト:
[{"name": "Router1", "type": "router"}, {"name": "SwitchA", "type": "switch"}, ...]
- エッジリスト:
[{"from": "Router1", "from_port": "GigabitEthernet1/0", "to": "SwitchA", "to_port": "GigabitEthernet0/1"}, ...]
テキストパースには、Pythonの正規表現 (re
モジュール) や、より高度なパースライブラリ (TTP, TextFSMなど) を利用することができます。LLDP/CDPの出力フォーマットはベンダーやバージョンによって異なるため、汎用的なパース処理を実装するか、利用する機器の出力に合わせて調整が必要です。
例えば、NetmikoとTextFSMを組み合わせると、CLIコマンド出力を構造化されたリストや辞書に変換できます。
from netmiko import ConnectHandler
from textfsm import TextFSM
import yaml
# ... Netmiko接続部分省略 ...
try:
with ConnectHandler(**device) as net_connect:
output = net_connect.send_command("show lldp neighbor detail")
# TextFSMテンプレートファイル (*.textfsm) を読み込む
# 適切なテンプレートは事前に用意するか、NAPALMのコミュニティなどで共有されているものを使用します。
template_file = 'path/to/your/lldp_neighbor_detail.textfsm'
with open(template_file) as f:
fsm = TextFSM(f)
parsed_data = fsm.ParseText(output)
# parsed_dataはヘッダーとデータのリストのリストになります。
# 例: parsed_data = [['Router2', 'GigabitEthernet0/1', 'Router1', 'GigabitEthernet1/0', ...], ...]
# この parsed_data からエッジリスト形式に変換するロジックを実装します。
edges = []
# parsed_dataをループしてedgesリストを作成
# テンプレートとデータ構造に合わせて実装してください。
# for item in parsed_data:
# edges.append({
# "from": item[2], # 例: Neighbor System Name
# "from_port": item[3], # 例: Neighbor Port ID
# "to": device['host'], # 自機器のホスト名
# "to_port": item[1] # 例: Local Port ID
# })
# 必要に応じてノードリストもここや別途の情報収集から作成します。
nodes = [{"name": device['host'], "type": "unknown"}] # 自機器を追加
# for edge in edges:
# # edgesに含まれるユニークな機器名をノードリストに追加
# pass # ノードリスト作成ロジック
print("--- Parsed Edges ---")
print(edges)
print("------------------")
except Exception as e:
print(f"Error: {e}")
このステップでは、収集した隣接情報をもとに、どの機器(ノード)がどの機器(ノード)と、どのインターフェース(ポート)で接続されているか(エッジ)を明確にすることが重要です。重複するノードやエッジを整理し、一意なリストを作成します。
3. 構成図の描画
整形されたノードとエッジのリストがあれば、様々な描画ツールを使って構成図を自動生成できます。Pythonから手軽に利用できるツールとして、Graphvizが挙げられます。Graphvizはグラフ構造(ノードとエッジの関係)を記述するためのDOT言語を解釈し、SVGやPNGなどの画像ファイルを生成できます。PythonにはGraphvizを操作するためのライブラリ (graphviz
パッケージ) が提供されています。
Graphvizライブラリを使った簡単な描画コード例を示します。
from graphviz import Digraph
# 仮のノードとエッジのデータ (前ステップで生成されたもの)
nodes = [
{"name": "Router1", "type": "router"},
{"name": "SwitchA", "type": "switch"},
{"name": "ServerB", "type": "server"},
]
edges = [
{"from": "Router1", "from_port": "G1/0", "to": "SwitchA", "to_port": "G0/1"},
{"from": "SwitchA", "from_port": "G0/2", "to": "ServerB", "to_port": "eth0"},
]
# Digraphオブジェクトを作成 (方向ありグラフ)
# 方向なしグラフの場合は graphviz.Graph を使用します。
dot = Digraph(comment='Network Diagram')
# ノードを追加
for node in nodes:
# ノードのスタイルやラベルを調整できます。
# 例: dot.node(node['name'], label=f"{node['name']}\n({node['type']})")
dot.node(node['name'], node['name']) # シンプルに機器名だけをラベルに使用
# エッジを追加
for edge in edges:
# エッジにポート情報をラベルとして追加できます。
# 例: dot.edge(edge['from'], edge['to'], label=f"{edge['from_port']} - {edge['to_port']}")
dot.edge(edge['from'], edge['to']) # シンプルに接続線だけ
# DOT言語のソースを表示 (デバッグ用)
print("--- DOT Source ---")
print(dot.source)
print("------------------")
# 構成図をファイルに出力
# format='png', 'svg', 'jpeg' など指定可能
# render()はGraphvizの実行ファイルが必要です。
try:
# 例: diagram.gv というファイル名でDOTファイルを保存し、
# それをもとに diagram.gv.png (または指定したフォーマット) を生成
dot.render('network_diagram', view=False, format='png', cleanup=True)
print("Network diagram generated as network_diagram.png")
except Exception as e:
print(f"Error rendering diagram. Make sure Graphviz executable is in your PATH: {e}")
print("Attempting to save DOT file only.")
dot.save('network_diagram.gv') # Graphviz実行ファイルがない場合でもDOTファイルは保存可能
Graphvizのインストールが必要です。多くのOSでパッケージマネージャーからインストールできます(例: sudo apt install graphviz
や brew install graphviz
)。また、Pythonライブラリは pip install graphviz
でインストールできます。
実践的な考慮事項
- 認証情報の管理: ネットワーク機器へのアクセスに必要な認証情報は、ハードコーディングせず、安全な方法(環境変数、設定ファイル、専用ツールなど)で管理してください。
- エラーハンドリング: 機器への接続失敗、コマンド実行エラー、パースエラーなど、発生しうるエラーに対して適切なエラーハンドリングを実装することが重要です。
- ベンダー差分: CLIコマンドやLLDP/CDP出力のフォーマットはベンダーによって大きく異なります。複数のベンダーを扱う場合は、それぞれの差異を吸収するためのパースロジックやテンプレートが必要になります。NAPALMのようなライブラリは、このベンダー差分を吸収するための抽象化レイヤーを提供しています。
- 情報の網羅性: LLDP/CDP情報は隣接する機器の情報しか提供しません。ネットワーク全体を把握するには、すべての機器から情報を収集し、それらを統合する必要があります。また、物理的な接続だけでなく、論理的な接続(VLAN、トンネルなど)を表現したい場合は、さらに詳細な情報収集とパースが必要になります。
- 自動更新とバージョン管理: 構成図を常に最新に保つために、定期的にスクリプトを実行する仕組み(Cronジョブ、CI/CDパイプラインなど)を構築し、生成された構成図ファイルをGitなどでバージョン管理することが推奨されます。
- 大規模環境: 機器数が非常に多い環境では、すべての機器から同時に情報を収集すると負荷が高くなる可能性があります。並列処理の導入や、段階的な情報収集を検討する必要があります。また、非常に複雑なネットワークはGraphvizで描画すると見づらくなる場合もあるため、必要に応じて手動での調整や、より高機能な描画ツール/サービスとの連携も考慮します。
まとめ
Pythonを使うことで、ネットワーク機器からの情報収集から構成図の自動生成までを一貫して行うことが可能です。CLIコマンド実行、パース、そしてGraphvizのような描画ツールとの連携により、手動での作業を大幅に削減し、常に最新のネットワーク構成を視覚的に把握できるようになります。
特に、ネットワーク構成にあまり馴染みがないシステムエンジニアやインフラエンジニアの方にとって、この自動化手法は現状把握の強力な助けとなります。今回紹介した基本的な手法を応用し、ご自身の環境に合わせたカスタマイズを行うことで、より実践的なネットワーク自動化の一歩を踏み出すことができるでしょう。今後は、収集した構成情報と他のインフラ情報(サーバー、アプリケーションなど)を組み合わせた、よりリッチな構成管理や、IaCツールとの連携についても検討を進めることが可能です。