Pythonとncclientで始めるNETConfネットワーク自動化入門
はじめに
ネットワーク機器の自動化は、現代のインフラ運用において不可欠な要素となっています。多くのエンジニアがCLI操作の自動化から着手しますが、CLIの出力は不安定でパースが難しいという課題があります。より構造的で信頼性の高い自動化を実現するためには、ネットワーク機器が提供するAPIを活用することが有効です。
本記事では、Pythonを用いてネットワーク機器のAPIを操作する手法として、NETConfプロトコルに焦点を当てます。特に、PythonでNETConfクライアントを実装するためのデファクトスタンダードライブラリである ncclient
を使用した基本的なネットワーク自動化の方法について解説します。
CLIベースの自動化経験はあるものの、NETConfやAPI操作はこれからというシステムエンジニア・インフラエンジニアの皆様に向けて、ncclient
の導入から基本的な操作までを実践的なコード例とともにご紹介します。
なぜNETConfなのか? API自動化の利点
従来のCLI操作によるネットワーク自動化は、show running-config
のようなコマンドを実行し、そのテキスト出力を正規表現などでパースして必要な情報を抽出したり、設定コマンドのシーケンスを送信したりする方法が主流でした。しかし、この方法は以下のような課題を抱えています。
- 出力形式の揺れ: 機器のOSバージョンアップやベンダーの違いによって、コマンドの出力形式が変更されることがあり、パーススクリプトのメンテナンスコストが高くなります。
- 状態管理の困難さ: 設定の適用が成功したか、あるいは機器がどのような状態にあるかを正確に判断するためには、複数のコマンド出力やログを複雑に解析する必要が生じます。
- トランザクション性の欠如: 複数の設定変更を一度に行う際に、途中でエラーが発生した場合に全ての設定を元に戻す(ロールバックする)ことが困難です。
これに対し、NETConfのようなAPIを用いた自動化は、これらの課題を解決する手段となります。
- 構造化されたデータ: NETConfはXML(またはJSON)形式で設定情報や運用状態を取得・設定するため、パースが容易でプログラムによる扱いに適しています。
- モデル駆動: YANGデータモデリング言語によってネットワーク機器の機能や設定項目が構造的に定義されており、自動化ツールはこのモデルを参照して操作を行います。これにより、抽象度が高く、ベンダー差を吸収しやすい自動化が可能になります。
- トランザクション機能: NETConfは、候補設定(candidate datastore)に対して変更を行い、問題がなければまとめて適用(commit)するといったトランザクション機能を提供します。これにより、設定変更の信頼性が向上し、失敗時には容易にロールバックできます。
NETConfは、SSH上で動作し、TCPポート830を使用するのが一般的です(SSHデフォルトポートである22を使用する場合もあります)。クライアント(自動化スクリプト)とサーバー(ネットワーク機器)間でRPC(Remote Procedure Call)メッセージを交換することで、機器の操作を行います。
ncclientの導入
ncclient
はPythonでNETConfクライアントを実装するためのライブラリです。pipを使って簡単にインストールできます。
pip install ncclient lxml
lxml
はXMLデータを効率的に扱うためのライブラリで、ncclient
が依存しているため一緒にインストールします。
ncclientを使った基本的な接続
ネットワーク機器への接続は、ホスト名またはIPアドレス、ユーザー名、パスワード(またはSSHキー)を指定して行います。
import logging
from ncclient import manager
# ログ設定 (デバッグ情報を表示する場合)
# logging.basicConfig(level=logging.DEBUG)
def connect_netconf(host, port, user, password):
"""
指定された情報でNETConfセッションを確立します。
Args:
host (str): 接続先ネットワーク機器のホスト名またはIPアドレス。
port (int): NETConfポート番号 (通常 830)。
user (str): 認証ユーザー名。
password (str): 認証パスワード。
Returns:
ncclient.manager.Manager: 確立されたセッションマネージャーオブジェクト。
"""
try:
# SSHキーを使用する場合は password=None, key_filename='path/to/key' を指定
conn = manager.connect(
host=host,
port=port,
username=user,
password=password,
hostkey_verify=False, # 実際の本番環境ではhostkey_verify=Trueとし、既知のホスト設定を正しく行う必要があります
device='generic' # 機器の種類に合わせて指定 (例: cisco_iosxe, juniper)。'generic'は広範な機器で動作しますが、特定の機能は制限される場合があります。
)
print(f"Successfully connected to {host}")
return conn
except Exception as e:
print(f"Failed to connect to {host}: {e}")
return None
# 使用例 (実際には適切な接続情報を設定してください)
if __name__ == "__main__":
NETCONF_HOST = 'your_device_ip' # ネットワーク機器のIPアドレスまたはホスト名
NETCONF_PORT = 830 # NETConfポート
NETCONF_USER = 'your_username' # ユーザー名
NETCONF_PASSWORD = 'your_password' # パスワード (またはSSHキー)
with connect_netconf(NETCONF_HOST, NETCONF_PORT, NETCONF_USER, NETCONF_PASSWORD) as m:
if m:
print("Connection capabilities:")
for capability in m.server_capabilities:
print(f" - {capability}")
# ここに他の操作を追加
print("Connection closed.")
manager.connect()
関数で接続を確立します。with
ステートメントを使用することで、セッション終了時に自動的に接続が閉じられるため便利です。hostkey_verify=False
は検証を無効にしていますが、セキュリティ上、本番環境では必ず有効化し、既知のホスト情報を適切に管理してください。device
パラメータは、特定のベンダーやOS向けに最適化されたドライバを選択できますが、generic
は多くの機器で基本的な操作が可能です。
NETConf RPCの実行例: 設定の取得 (get-config
)
NETConfの最も一般的な操作の一つは、機器の設定情報を取得することです。これには get-config
RPCを使用します。取得したい設定情報全体、または特定の要素をフィルタリングして取得できます。
以下は、機器の running configuration 全体を取得する例です。
# 上記の接続確立コードに続けて実行
if m:
print("\nGetting running configuration...")
try:
# datastore='running' で running configuration を指定
# filter=None でフィルタリングなし (全取得)
result = m.get_config(source='running')
print("Received configuration (first 500 chars):")
# XML形式の応答が得られる
print(result.data_xml.strip()[:500] + "...")
# 取得したXMLデータをパースして特定情報を抽出することも可能
# 例: lxmlを使ってhostnameを取得 (XML構造は機器やYANGモデルによる)
# from lxml import etree
# root = etree.fromstring(result.data_xml.encode('utf-8'))
# hostname_element = root.find('.//{*}hostname') # 適切なXPathを指定
# if hostname_element is not None:
# print(f"Hostname: {hostname_element.text}")
except Exception as e:
print(f"Failed to get configuration: {e}")
m.get_config()
メソッドを使用します。source='running'
は、現在の稼働コンフィグを取得することを意味します。他にも、起動時コンフィグを示す startup
(対応している機器の場合)や、編集中の候補コンフィグを示す candidate
(対応している機器の場合)などがあります。
result.data_xml
には、XML形式の応答データが含まれています。このXMLデータをPythonのXMLパースライブラリ(例: lxml
)を使って解析することで、必要な設定値を構造的に取得できます。CLI出力のパースに比べて、形式が標準化されているため、より安定したデータ処理が可能です。
特定の情報だけを取得したい場合は、filter
パラメータにXML形式のフィルタ条件を指定します。フィルタの書き方は、機器がサポートするYANGモデルの構造に依存します。
NETConf RPCの実行例: 設定の変更 (edit-config
, commit
)
NETConfを使って機器の設定を変更することも可能です。これには主に edit-config
と commit
RPCを使用します。多くの機器では、設定変更を直接 running config に適用するのではなく、まず候補設定(candidate datastore)に対して変更を加え、その後 commit
RPCで running config に反映させるという2段階のプロセスを取ります。これは、設定変更の原子性を保ち、途中で問題が発生した場合に容易にロールバックできるようにするためです。
以下は、簡単な設定変更の例です(機器が candidate datastore をサポートしていることを前提とします)。
# 上記の接続確立コードに続けて実行
if m:
print("\nEditing configuration...")
# 設定変更内容をXML形式で定義
# このXML構造は機器がサポートするYANGモデルに依存します
# 例: Cisco IOS XE で hostname を変更する場合のYANGモデル(一部簡略化)に合わせたXML
config_payload = """
<config>
<native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
<hostname>my-new-hostname</hostname>
</native>
</config>
"""
try:
# candidate datastore に対して設定を編集
# default_operation='merge' は既存設定とマージすることを意味します
edit_result = m.edit_config(target='candidate', config=config_payload, default_operation='merge')
print("Edit-config successful.")
# commit RPC で候補設定を running config に反映
commit_result = m.commit()
print("Commit successful.")
# ロールバック機能に対応している機器であれば、
# m.discard_changes() で commit 前の変更を破棄
# m.rollback() で直前の commit を元に戻す (要検証)
except Exception as e:
print(f"Failed to edit or commit configuration: {e}")
設定変更の内容は、config_payload
という変数にXML形式で定義しています。このXMLの構造は、対象機器がNETConfで公開しているYANGデータモデルに厳密に従う必要があります。YANGモデルは、機器の機能を構造化し、NETConf経由で操作可能な要素や属性を定義しています。
m.edit_config()
で、指定したターゲット (candidate
) に対して設定変更を適用します。default_operation='merge'
は、既存設定に今回指定した設定を追加・更新することを意味します。他にも replace
や delete
といった操作があります。
m.commit()
で、candidate
datastore に加えた変更を running
datastore に反映させます。この時点で、設定変更が機器に実際に適用されます。
実践的な考慮事項
ncclient
とNETConfを使った自動化を現場で利用する際には、いくつかの重要な考慮事項があります。
- 認証情報の管理: ユーザー名やパスワードをスクリプト内に直接記述するのは危険です。環境変数、設定ファイル、または専用のシークレット管理ツール(HashiCorp Vault, CyberArkなど)を使用して安全に管理してください。
- エラーハンドリング: NETConf RPCの実行中にエラーが発生した場合、
ncclient
は例外を発生させます。try...except
ブロックを使用して、これらの例外を適切にキャッチし、エラーメッセージをログに出力したり、必要に応じて処理を中断・再試行したりするロジックを実装することが重要です。NETConfのエラー応答はXML形式で詳細なエラー情報を含んでいるため、それを解析して原因特定に役立てることも可能です。 - 冪等性: 同じスクリプトを複数回実行しても、最終的な機器の状態が同じになるようにスクリプトを設計することが望ましいです(冪等性)。
edit-config
のdefault_operation='merge'
は冪等性の実現に役立ちますが、より複雑なシナリオでは、設定変更前に現在の状態を確認し、必要な変更のみを適用するロジックが必要になる場合があります。 - YANGデータモデル: NETConfの操作は、機器がサポートするYANGデータモデルに大きく依存します。対象機器がどのようなYANGモデルを提供しているか、そのモデルの構造はどうなっているかを把握することが、効果的なAPI自動化には不可欠です。多くのベンダーがWebサイトでYANGモデルを公開しています。
- トランザクションとロールバック:
candidate
とcommit
を利用するワークフローはトランザクション性を提供し、信頼性の高い設定変更を可能にします。また、多くのNETConf対応機器はrollback
機能もサポートしています。設定変更スクリプトには、失敗した場合にdiscard-changes
やrollback
RPCを使って機器の状態を安全に戻す処理を含めることを検討してください。
CLI自動化との使い分け
CLIベースの自動化とAPI(NETConf/RESTConfなど)による自動化は、どちらか一方だけが優れているというものではなく、状況に応じて使い分ける、あるいは組み合わせて使用するものです。
- CLI自動化(Netmiko/Paramiko等): APIが提供されていない、あるいはAPIでは操作できないレガシー機器。単純な情報取得や、決まったコマンド実行のみで完結する場合。トラブルシューティングや一時的な確認作業など、柔軟性が求められる場合。
- API自動化(ncclient/requests等): NETConf/RESTConfがサポートされている機器。設定の変更や検証を構造的かつ信頼性高く行いたい場合。IaCツール(Ansible, Terraformなど)との連携を前提とする場合。大量の機器に対して並列かつ効率的に操作を行いたい場合。
特に、新しい機器や仮想ネットワーク機能ではAPIが重視される傾向にあります。将来的にはAPIによる自動化が主流になっていくと考えられます。
まとめ
本記事では、Pythonライブラリ ncclient
を使用して、NETConfプロトコルによるネットワーク機器の基本的な自動操作を行う方法について解説しました。
ncclient
を利用することで、CLIのテキストパースに依存しない、構造的で信頼性の高いネットワーク自動化を実現できます。NETConfの get-config
や edit-config
、commit
といったRPCを適切に利用することで、機器の設定情報の取得や変更を安全に行うことが可能です。
NETConfとYANGデータモデルは、ネットワーク自動化の可能性を大きく広げます。この記事が、Pythonスキルを活かしてネットワーク自動化に取り組む皆様にとって、API自動化への第一歩を踏み出すきっかけとなれば幸いです。
今後は、より詳細なフィルタリング、YANGモデルの活用、エラー回復処理、そしてIaCツールとの連携など、実践的な応用例についてもご紹介していく予定です。