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

Pythonによるネットワーク構成図自動生成:データ収集から可視化まで

Tags: Python, ネットワーク自動化, 構成図, Graphviz, Netmiko, データ収集, 可視化

システムやインフラの全体像を把握する上で、ネットワーク構成図は非常に重要なドキュメントです。しかし、機器構成の変更や拡張が頻繁に行われる現場では、構成図を手動で最新の状態に保つことは容易ではありません。特に、ネットワーク機器の操作や構成情報にあまり慣れていない場合、現状把握に時間がかかり、自動化を進める上での障壁となることもあります。

この記事では、Pythonのスキルを活かして、ネットワーク機器から情報を収集し、構成図を自動生成する手法について解説します。これにより、常に最新のネットワーク構成を視覚的に把握できるようになり、インフラ運用や自動化の効率化に貢献できます。

ネットワーク構成図自動生成のステップ

ネットワーク構成図を自動生成するためには、主に以下のステップが必要となります。

  1. 情報の収集: ネットワーク機器から構成図作成に必要な情報を収集します。
  2. データ整形: 収集した生データを、図の描画に適した構造化されたデータに整形します。
  3. 関係性の特定: 機器間の接続関係などの論理的な関係性を特定します。
  4. 構成図の描画: 整形・特定した情報をもとに構成図を描画します。

これらのステップをPythonを使って自動化する方法を見ていきましょう。

1. 情報の収集

構成図を描くためには、最低限以下の情報が必要になります。

これらの情報を収集するための一般的な方法としては、以下のものが挙げられます。

ここでは、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の出力はテキスト形式です。構成図を描画するためには、「ノード」(機器)と「エッジ」(接続)の関係性を明確にした構造化データが必要です。テキスト出力をパースして、以下のような形式のデータを生成します。

テキストパースには、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 graphvizbrew install graphviz)。また、Pythonライブラリは pip install graphviz でインストールできます。

実践的な考慮事項

まとめ

Pythonを使うことで、ネットワーク機器からの情報収集から構成図の自動生成までを一貫して行うことが可能です。CLIコマンド実行、パース、そしてGraphvizのような描画ツールとの連携により、手動での作業を大幅に削減し、常に最新のネットワーク構成を視覚的に把握できるようになります。

特に、ネットワーク構成にあまり馴染みがないシステムエンジニアやインフラエンジニアの方にとって、この自動化手法は現状把握の強力な助けとなります。今回紹介した基本的な手法を応用し、ご自身の環境に合わせたカスタマイズを行うことで、より実践的なネットワーク自動化の一歩を踏み出すことができるでしょう。今後は、収集した構成情報と他のインフラ情報(サーバー、アプリケーションなど)を組み合わせた、よりリッチな構成管理や、IaCツールとの連携についても検討を進めることが可能です。