PythonによるネットワークVLAN設定の自動化:実践スクリプト例
ネットワークインフラの管理において、VLAN設定は日常的に発生する作業の一つです。サーバーの増設や移設、セキュリティポリシーの変更などに伴い、VLANの作成、削除、インターフェースへの割り当てといった作業が必要となります。これらの作業を手動で行う場合、設定ミスや作業時間の増大といった課題がつきまといます。
特に、クラウドインフラの自動化やCI/CDパイプラインの構築に習熟されているエンジニアの方々にとって、ネットワーク機器のCLI操作は馴染みが薄く、効率化のボトルネックとなりがちです。Pythonを活用することで、このようなネットワークVLAN設定作業を自動化し、人的ミスを減らし、作業時間を大幅に短縮することが可能になります。
この記事では、Pythonを使用してネットワーク機器のVLAN設定を自動化するための具体的な手法とスクリプト例をご紹介します。
VLAN設定自動化の必要性とメリット
VLAN設定の手動作業には以下のような課題があります。
- 設定ミス: コマンド入力の誤りや設定手順の抜け漏れが発生しやすいです。
- 作業時間: 複数機器に対して同じ設定を行う場合、時間と労力がかかります。
- 属人化: 設定方法や手順が特定の担当者に依存しがちです。
- 変更管理: 誰がいつどのような設定変更を行ったかの追跡が困難になることがあります。
これらの課題は、Pythonによる自動化によって解決できます。自動化のメリットは以下の通りです。
- 正確性の向上: スクリプト化することで、常に同じ品質で設定が実行されます。
- 作業時間の短縮: 一度スクリプトを作成すれば、繰り返し迅速に実行できます。
- 標準化: 設定手順がコードとして共有され、チーム全体で利用できます。
- 変更の可視化: スクリプト自体をバージョン管理することで、設定変更の履歴を管理できます。
Pythonによるネットワーク機器操作の基本
Pythonでネットワーク機器を操作するには、主に以下の方法があります。
- CLI自動化: SSH/Telnet経由で機器に接続し、CLIコマンドを実行する方法です。
paramiko
やnetmiko
といったライブラリが広く使われます。直感的で、既存のCLI操作知識を活かしやすいという利点があります。 - API連携: ネットワーク機器が提供するAPI(RESTConf, NETConfなど)を利用する方法です。構造化データ(XML, JSON)で設定や状態を取得・変更でき、よりプログラムフレンドリーな操作が可能です。
ncclient
(NETConf)や各種ベンダーSDKなどが利用されます。 - 状態駆動型自動化:
NAPALM
やNornir
のようなライブラリ・フレームワークを利用し、機器の「状態」をコードで定義し、その状態に収束させるように自動的に操作を行う方法です。異なるベンダー機器の設定を抽象化できる利点があります。
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)
コードの解説:
ConnectHandler(**device_info)
: 辞書形式の接続情報を展開してConnectHandler
のインスタンスを作成します。with
ステートメントを使うことで、接続のクローズを保証します。device_type
: 接続するネットワーク機器の種類を指定します。netmiko
が対応している種類については公式ドキュメントを参照してください。getpass.getpass()
: パスワードなどの機密情報をスクリプト中にハードコードせず、実行時に入力させるための標準ライブラリです。セキュリティ上、推奨されます。send_config_set(config_commands)
: リスト形式で渡されたコンフィグレーションコマンドを、機器のコンフィグレーションモードで順に実行します。- エラーハンドリング:
try...except
ブロックで接続エラーやコマンド実行エラーを捕捉します。 - 冪等性: このスクリプトは単にコマンドを実行するだけです。もしVLAN IDが既に存在する場合、多くの機器ではエラーになるか、名前だけが変更されるなどの動作になります。真の冪等性を実現するには、事前にVLANの存在を確認し、必要ならスキップまたは変更するといったロジックを追加する必要があります(後述の確認スクリプトと組み合わせる)。
- 設定の保存:
net_connect.save_config()
やnet_connect.send_command('write memory')
などで設定を保存できますが、自動化スクリプトで安易に保存すると意図しない変更が保存されるリスクがあります。本番環境での利用には十分な検討が必要です。
スクリプト例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)
コードの解説:
send_config_set
を使って、インターフェースコンフィグレーションモードでのコマンドを実行しています。switchport mode access
とswitchport access vlan
はCisco IOSの例です。他のベンダー(Juniper, Aristaなど)ではコマンドが異なりますので、適切なコマンドに書き換える必要があります。- これも冪等性については考慮が必要です。既にVLANが割り当てられている場合の動作などを確認する必要があります。
スクリプト例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)
コードの解説:
send_command(command)
: 機器にコマンドを送信し、その出力結果を文字列として取得します。設定変更ではなく、状態確認コマンドに適しています。- CLI出力のパース:
re
モジュールを使った簡易的なパース例を示しています。CLI出力はフォーマットが崩れやすいため、より堅牢なパースにはTextFSM
やTTP
といったライブラリ、あるいはNAPALMのような標準化された手法の利用を検討すべきです。 - NAPALMの活用: コメントアウト部分でNAPALMを使った構造化データ取得の可能性に触れています。NAPALMは様々な機器から標準化された形式で情報を取得できるため、ベンダー差を吸収し、取得したデータをPythonで扱いやすくするのに役立ちます。
現場で応用するための考慮点
ご紹介したスクリプトは基本的な機能に限定されていますが、現場で利用するためにはさらに以下の点を考慮する必要があります。
- エラーハンドリングの強化: コマンド実行結果の成功・失敗判定、特定のキーワード(
% Error
,Invalid input detected
など)のチェック、リトライ処理などを実装します。 - 入力値の検証: VLAN IDやインターフェース名が有効な形式であるか、機器に存在するかなどを事前に検証します。
- 冪等性の確保: スクリプトを複数回実行しても同じ結果になるように、現在の設定を取得し、必要な変更のみを適用するロジックを組み込みます。
- インベントリ管理: 接続情報をYAMLやJSONなどのファイルで管理し、スクリプトが複数の機器に対して実行できるように汎用化します。
Nornir
のようなフレームワークはこの目的のために設計されています。 - 認証情報の安全な管理: パスワードなどをスクリプトファイルや環境変数に平文で置かず、Secrets ManagerやHashiCorp Vault、あるいは暗号化されたファイルなどで管理します。
- ベンダー対応: 異なるベンダーの機器に対応するため、
device_type
に応じたコマンドの分岐や、NAPALMのような抽象化ライブラリの利用を検討します。 - ログ記録: スクリプトの実行結果、成功・失敗、適用した設定内容などをログファイルに記録します。
- 設定のバックアップ: 設定変更前に現在の設定を自動でバックアップする機能を組み込むことで、問題発生時に素早くロールバックできるようにします。
ネットワーク自動化とIaC/CI/CD
ネットワーク自動化は、より広範なインフラ自動化や開発プロセス(IaC, CI/CD)と連携することで、その真価を発揮します。
- IaCとの連携: ネットワーク設定をコード(YAML, JSONなど)として定義し、Gitなどのバージョン管理システムで管理します。スクリプトは、この「設定ファイル」に基づいて機器に設定を適用する役割を担います。AnsibleのようなIaCツールと連携することで、サーバー、クラウド、ネットワークを含むシステム全体の構成管理を統一的に行えます。
- CI/CDパイプラインへの組み込み: サーバーやアプリケーションのデプロイと同時に、関連するVLAN設定やファイアウォール設定を自動的に変更するステップをCI/CDパイプラインに組み込みます。これにより、デプロイとネットワーク設定変更の間の手動連携が不要となり、リリースプロセスのスピードアップと信頼性向上に繋がります。スクリプトの変更(ネットワーク設定のコード化)をトリガーに、自動テストやステージング環境への適用を行うことも可能です。
まとめ
この記事では、Pythonとnetmiko
ライブラリを使ったネットワーク機器のVLAN設定自動化スクリプトの基本的な例をご紹介しました。手動での作業に比べて、自動化は設定の正確性、作業時間の短縮、運用効率の向上に大きく貢献します。
ネットワーク機器に直接的な操作経験が少なくても、Pythonスキルを活用することで、CLI自動化、API連携、あるいは状態駆動型のアプローチによってネットワーク設定をコード化し、自動化の対象に組み込むことが十分に可能です。
今回ご紹介したスクリプトをベースに、エラーハンドリングや冪等性、インベントリ管理といった考慮点を加えることで、より堅牢で実用的なネットワーク自動化スクリプトを構築できます。ぜひ、日々の運用業務にPythonによるネットワーク自動化を取り入れてみてください。