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

PythonによるネットワークVLAN設定の自動化:実践スクリプト例

Tags: Python, ネットワーク自動化, VLAN, Netmiko, スクリプト

ネットワークインフラの管理において、VLAN設定は日常的に発生する作業の一つです。サーバーの増設や移設、セキュリティポリシーの変更などに伴い、VLANの作成、削除、インターフェースへの割り当てといった作業が必要となります。これらの作業を手動で行う場合、設定ミスや作業時間の増大といった課題がつきまといます。

特に、クラウドインフラの自動化やCI/CDパイプラインの構築に習熟されているエンジニアの方々にとって、ネットワーク機器のCLI操作は馴染みが薄く、効率化のボトルネックとなりがちです。Pythonを活用することで、このようなネットワークVLAN設定作業を自動化し、人的ミスを減らし、作業時間を大幅に短縮することが可能になります。

この記事では、Pythonを使用してネットワーク機器のVLAN設定を自動化するための具体的な手法とスクリプト例をご紹介します。

VLAN設定自動化の必要性とメリット

VLAN設定の手動作業には以下のような課題があります。

これらの課題は、Pythonによる自動化によって解決できます。自動化のメリットは以下の通りです。

Pythonによるネットワーク機器操作の基本

Pythonでネットワーク機器を操作するには、主に以下の方法があります。

  1. CLI自動化: SSH/Telnet経由で機器に接続し、CLIコマンドを実行する方法です。paramikonetmikoといったライブラリが広く使われます。直感的で、既存のCLI操作知識を活かしやすいという利点があります。
  2. API連携: ネットワーク機器が提供するAPI(RESTConf, NETConfなど)を利用する方法です。構造化データ(XML, JSON)で設定や状態を取得・変更でき、よりプログラムフレンドリーな操作が可能です。ncclient(NETConf)や各種ベンダーSDKなどが利用されます。
  3. 状態駆動型自動化: NAPALMNornirのようなライブラリ・フレームワークを利用し、機器の「状態」をコードで定義し、その状態に収束させるように自動的に操作を行う方法です。異なるベンダー機器の設定を抽象化できる利点があります。

VLAN設定はCLIコマンドによる操作が一般的であり、今回はCLI自動化に特化したnetmikoを中心にスクリプト例をご紹介します。

netmikoを使ったVLAN設定スクリプト例

netmikoは、多数のネットワークベンダーおよびOSに対応した、SSH/TelnetによるCLI操作を効率化するためのライブラリです。接続情報の管理、コマンド実行、プロンプト判定などを自動で行います。

事前準備

netmikoをインストールします。

pip install netmiko

対象のネットワーク機器へのSSH接続情報を準備します。IPアドレス、SSHポート(デフォルト22)、ユーザー名、パスワードなどを設定します。

スクリプト例1:新しいVLANの作成

指定したVLAN IDと名前で新しいVLANを作成するスクリプトです。

from netmiko import ConnectHandler
import getpass
import sys

# 接続情報 (実際の環境に合わせて変更してください)
device = {
    'device_type': 'cisco_ios', # 機器の種類 (例: cisco_ios, juniper_junos, arista_eosなど)
    'host': 'YOUR_DEVICE_IP',
    'username': 'YOUR_USERNAME',
    'password': None, # スクリプト内に書かず、実行時に入力させるのが推奨
    'port': 22,
    'secret': None, # 特権EXECモードへの移行に必要であれば設定
}

def create_vlan(device_info, vlan_id, vlan_name):
    """
    指定したVLAN IDと名前で新しいVLANを作成する関数
    """
    try:
        # パスワードを安全に入力させる
        device_info['password'] = getpass.getpass(prompt=f"Enter password for {device_info['username']}@{device_info['host']}: ")
        if device_info.get('secret') is not None:
             device_info['secret'] = getpass.getpass(prompt=f"Enter enable password for {device_info['host']}: ")

        print(f"Connecting to {device_info['host']}...")
        with ConnectHandler(**device_info) as net_connect:
            print("Connection successful.")

            # コンフィグレーションモードに移行し、VLAN設定コマンドを実行
            # コマンドは機器の種類によって異なります。以下はCisco IOSの例です。
            config_commands = [
                f'vlan {vlan_id}',
                f'name {vlan_name}'
            ]

            print(f"Applying configuration: {config_commands}")
            output = net_connect.send_config_set(config_commands)
            print("Configuration output:")
            print(output)

            # 設定を保存するかは状況に応じて判断してください。
            # print("Saving configuration...")
            # save_output = net_connect.save_config()
            # print(save_output)

        print(f"VLAN {vlan_id} ({vlan_name}) creation attempt completed.")

    except Exception as e:
        print(f"An error occurred: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python create_vlan.py <vlan_id> <vlan_name>")
        sys.exit(1)

    vlan_id_to_create = sys.argv[1]
    vlan_name_to_create = sys.argv[2]

    # 確認メッセージ
    confirm = input(f"Proceed with creating VLAN {vlan_id_to_create} ({vlan_name_to_create}) on {device['host']}? (yes/no): ")
    if confirm.lower() == 'yes':
        create_vlan(device, vlan_id_to_create, vlan_name_to_create)
    else:
        print("Operation cancelled.")
        sys.exit(0)

コードの解説:

スクリプト例2:インターフェースへのVLAN割り当て

指定したインターフェースを特定のVLANに割り当てる(アクセスポートとして設定する)スクリプト例です。

from netmiko import ConnectHandler
import getpass
import sys

# 接続情報 (実際の環境に合わせて変更してください)
device = {
    'device_type': 'cisco_ios', # 機器の種類 (例: cisco_ios, juniper_junos, arista_eosなど)
    'host': 'YOUR_DEVICE_IP',
    'username': 'YOUR_USERNAME',
    'password': None,
    'port': 22,
    'secret': None,
}

def assign_vlan_to_interface(device_info, interface_name, vlan_id):
    """
    指定したインターフェースをアクセスポートとして指定VLANに割り当てる関数
    """
    try:
        device_info['password'] = getpass.getpass(prompt=f"Enter password for {device_info['username']}@{device_info['host']}: ")
        if device_info.get('secret') is not None:
             device_info['secret'] = getpass.getpass(prompt=f"Enter enable password for {device_info['host']}: ")

        print(f"Connecting to {device_info['host']}...")
        with ConnectHandler(**device_info) as net_connect:
            print("Connection successful.")

            # インターフェース設定コマンド (Cisco IOS例)
            # 他ベンダーの場合は適切なコマンドに変更してください。
            config_commands = [
                f'interface {interface_name}',
                'switchport mode access', # アクセスポートとして設定
                f'switchport access vlan {vlan_id}' # 指定VLANを割り当て
            ]

            print(f"Applying configuration: {config_commands}")
            output = net_connect.send_config_set(config_commands)
            print("Configuration output:")
            print(output)

        print(f"VLAN {vlan_id} assigned to interface {interface_name} attempt completed.")

    except Exception as e:
        print(f"An error occurred: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python assign_vlan.py <interface_name> <vlan_id>")
        sys.exit(1)

    interface = sys.argv[1]
    vlan_id_to_assign = sys.argv[2]

    confirm = input(f"Proceed with assigning VLAN {vlan_id_to_assign} to interface {interface} on {device['host']}? (yes/no): ")
    if confirm.lower() == 'yes':
        assign_vlan_to_interface(device, interface, vlan_id_to_assign)
    else:
        print("Operation cancelled.")
        sys.exit(0)

コードの解説:

スクリプト例3:VLAN設定の確認

現在のVLAN設定(VLANリスト、インターフェースへの割り当て状況など)を確認するスクリプト例です。

from netmiko import ConnectHandler
import getpass
import sys
import re # CLI出力のパースにreモジュールを使う例

# 接続情報 (実際の環境に合わせて変更してください)
device = {
    'device_type': 'cisco_ios', # 機器の種類
    'host': 'YOUR_DEVICE_IP',
    'username': 'YOUR_USERNAME',
    'password': None,
    'port': 22,
    'secret': None,
}

def verify_vlan_config(device_info):
    """
    VLAN設定を確認する関数
    """
    try:
        device_info['password'] = getpass.getpass(prompt=f"Enter password for {device_info['username']}@{device_info['host']}: ")
        if device_info.get('secret') is not None:
             device_info['secret'] = getpass.getpass(prompt=f"Enter enable password for {device_info['host']}: ")

        print(f"Connecting to {device_info['host']}...")
        with ConnectHandler(**device_info) as net_connect:
            print("Connection successful.")

            # VLAN一覧を表示するコマンド (Cisco IOS例)
            # 他ベンダーの場合は適切なコマンドに変更してください。
            command_vlan_brief = 'show vlan brief'
            print(f"\nExecuting command: {command_vlan_brief}")
            output_vlan_brief = net_connect.send_command(command_vlan_brief)
            print("Command output:")
            print(output_vlan_brief)

            # インターフェースの状態を表示するコマンド (Cisco IOS例)
            command_int_status = 'show interface status'
            print(f"\nExecuting command: {command_int_status}")
            output_int_status = net_connect.send_command(command_int_status)
            print("Command output:")
            print(output_int_status)

            # ★ CLI出力のパース例(簡易版) ★
            # show vlan briefの出力からVLAN IDと名前を抽出
            vlan_data = {}
            # 出力例:
            # 1    default                        active    Fa0/1, Fa0/2
            # 10   Servers                        active    Gi1/1
            # 20   Clients                        active
            lines = output_vlan_brief.splitlines()
            # ヘッダー行などをスキップし、VLAN情報の行を処理
            for line in lines:
                match = re.match(r'^\s*(\d+)\s+([\w-]+)\s+active\s*(.*)$', line)
                if match:
                    vlan_id, vlan_name, interfaces_str = match.groups()
                    interfaces = [iface.strip() for iface in interfaces_str.split(',') if iface.strip()]
                    vlan_data[vlan_id] = {
                        'name': vlan_name,
                        'interfaces': interfaces
                    }

            print("\nParsed VLAN Data:")
            import json
            print(json.dumps(vlan_data, indent=2))

            # ★ NAPALMの活用 ★
            # NAPALMは、構造化データでネットワーク機器の状態を取得するのに優れています。
            # netmikoと組み合わせて、CLIで設定変更し、NAPALMで状態確認といった使い分けも可能です。
            # 例:
            # from napalm import get_network_driver
            # driver = get_network_driver(device_info['device_type'])
            # optional_args = {'secret': device_info['secret']} if device_info.get('secret') else {}
            # napalm_device = driver(device_info['host'], device_info['username'], device_info['password'], optional_args=optional_args)
            # napalm_device.open()
            # vlans = napalm_device.get_vlans() # 標準化されたVLAN情報取得メソッド
            # interfaces = napalm_device.get_interfaces() # 標準化されたインターフェース情報取得メソッド
            # napalm_device.close()
            # print("\nNAPALM VLAN Data (Example using napalm library if installed):")
            # print(json.dumps(vlans, indent=2))
            # print("\nNAPALM Interface Data (Example using napalm library if installed):")
            # print(json.dumps(interfaces, indent=2))


    except Exception as e:
        print(f"An error occurred: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    confirm = input(f"Proceed with verifying VLAN configuration on {device['host']}? (yes/no): ")
    if confirm.lower() == 'yes':
        verify_vlan_config(device)
    else:
        print("Operation cancelled.")
        sys.exit(0)

コードの解説:

現場で応用するための考慮点

ご紹介したスクリプトは基本的な機能に限定されていますが、現場で利用するためにはさらに以下の点を考慮する必要があります。

ネットワーク自動化とIaC/CI/CD

ネットワーク自動化は、より広範なインフラ自動化や開発プロセス(IaC, CI/CD)と連携することで、その真価を発揮します。

まとめ

この記事では、Pythonとnetmikoライブラリを使ったネットワーク機器のVLAN設定自動化スクリプトの基本的な例をご紹介しました。手動での作業に比べて、自動化は設定の正確性、作業時間の短縮、運用効率の向上に大きく貢献します。

ネットワーク機器に直接的な操作経験が少なくても、Pythonスキルを活用することで、CLI自動化、API連携、あるいは状態駆動型のアプローチによってネットワーク設定をコード化し、自動化の対象に組み込むことが十分に可能です。

今回ご紹介したスクリプトをベースに、エラーハンドリングや冪等性、インベントリ管理といった考慮点を加えることで、より堅牢で実用的なネットワーク自動化スクリプトを構築できます。ぜひ、日々の運用業務にPythonによるネットワーク自動化を取り入れてみてください。