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

現場で役立つPython:ネットワーク機器OSパッチ適用を自動化する実践手法

Tags: Python, ネットワーク自動化, Netmiko, Nornir, OSパッチ, 運用自動化, 実践スクリプト, NAPALM

はじめに

システム運用において、ネットワーク機器のOSパッチ適用はセキュリティの維持や機能改善のために不可欠な作業です。しかし、対象機器の多さ、作業手順の複雑さ、そして失敗時の影響の大きさから、多くの場合は手作業または部分的なスクリプトによる対応となり、運用負荷やヒューマンエラーのリスクが課題となります。

近年、Pythonを用いたネットワーク自動化の取り組みが進んでいます。Pythonは豊富なライブラリエコシステムと高い汎用性を持ち、開発ライフサイクルやインフラ自動化の文脈で培われた知見をネットワーク領域に応用することが可能です。この記事では、Pythonを活用してネットワーク機器のOSパッチ適用作業を自動化するための実践的な手法と、具体的なスクリプト例についてご紹介します。ネットワーク機器の直接的な操作に不慣れなエンジニアの方でも、Pythonスキルを活かして運用効率と安全性を高めるためのヒントとなれば幸いです。

ネットワーク機器OSパッチ適用自動化のプロセス

ネットワーク機器のOSパッチ適用プロセスは、一般的に以下のフェーズに分解できます。自動化を検討する際も、これらのフェーズごとにどのような処理を行うかを定義することが重要です。

  1. 事前準備フェーズ:
    • 適用対象機器の選定と情報の収集(機種、現在のバージョン、適用要件など)
    • 新しいOSイメージファイルのダウンロードと、自動化サーバ/ストレージへの配置
    • 適用前のコンフィグやステータス情報のバックアップ取得
    • 適用前のヘルスチェック(機器の状態確認、疎通確認など)
  2. パッチ適用フェーズ:
    • 新しいOSイメージファイルの機器への転送
    • ブートイメージの設定変更(次回起動時のイメージ指定)
    • 機器の再起動
  3. 適用後確認フェーズ:
    • 機器の起動確認
    • OSバージョンの確認
    • 適用前の状態との差異確認(コンフィグ、インターフェース状態など)
    • 疎通確認、サービス稼働確認
    • 適用後のヘルスチェック
  4. 後処理/レポートフェーズ:
    • 適用結果の記録
    • 関係者への通知
    • (必要に応じて)旧OSイメージファイルの削除

Pythonによる自動化では、これらの各フェーズで必要な処理を実行するスクリプト群を構築することを目指します。特に、ファイル転送、CLIコマンドの実行、機器状態の取得・解析といった操作でPythonライブラリが力を発揮します。

Pythonライブラリの活用

ネットワーク機器とのインタラクションにおいて、Pythonにはいくつかの強力なライブラリがあります。OSパッチ適用自動化では、主に以下のライブラリが有用です。

具体的なスクリプト例と実装のポイント

ここでは、NetmikoとNornirを中心に据えた自動化スクリプトの基本的な考え方とコード例を示します。

前提準備

Python環境に以下のライブラリをインストールしておきます。

pip install netmiko paramiko nornir napalm

Nornirを使用する場合、対象機器リストを定義したインベントリファイル(例: hosts.yaml)が必要です。

# hosts.yaml (例)
router01:
  hostname: 192.168.1.101
  platform: cisco_ios
  username: admin
  password: password123
  groups:
    - routers
  data:
    os_image_file: "ios_XE.bin" # 適用するイメージファイル名
    os_image_path: "/flash/" # イメージファイルの転送先パス
    tftp_server: "192.168.1.1" # TFTP/SCPサーバのアドレス

switch01:
  hostname: 192.168.1.102
  platform: cisco_ios
  username: admin
  password: password123
  groups:
    - switches
  data:
    os_image_file: "cat9k_iosxe.bin"
    os_image_path: "/flash/"
    tftp_server: "192.168.1.1"

# etc...

認証情報は、インベントリファイルに直接記述するのではなく、環境変数やSecrets Managementツール(Vaultなど)と連携させて安全に管理することが強く推奨されます。Nornirは認証情報を vars.yaml や環境変数から読み込む機能も提供しています。

OSイメージファイルの転送

NetmikoやParamikoのSCP/SFTP機能、あるいは機器側のTFTP/SCPクライアント機能を利用して、OSイメージファイルを機器に転送します。

Netmikoを使った例(TFTP/SCPクライアント機能を使用):

from nornir import InitNornir
from nornir_netmiko.tasks import netmiko_send_command

def transfer_os_image(task):
    # TFTPやSCPでファイル転送するコマンドはベンダーやOSによって異なる
    # ここではCisco IOS XEの例(SCPを利用)
    transfer_command = f"copy scp://{task.host['data']['tftp_server']}/{task.host['data']['os_image_file']} {task.host['data']['os_image_path']}{task.host['data']['os_image_file']}"

    print(f"Attempting to transfer file to {task.host.name}...")
    # ファイル転送コマンド実行。確認プロンプトが出る場合があるためexpect_stringを使用
    result = task.run(
        task=netmiko_send_command,
        command_string=transfer_command,
        use_text=True, # CLIコマンドの結果をテキスト形式で取得
        expect_string=r'[#>]' # 機器のプロンプトを待つ
    )
    print(f"File transfer command sent to {task.host.name}")
    print(result.result) # コマンド結果を表示

    # ファイル転送が成功したかの確認コマンドを実行
    verify_command = f"dir {task.host['data']['os_image_path']}{task.host['data']['os_image_file']}"
    verify_result = task.run(
        task=netmiko_send_command,
        command_string=verify_command,
        use_text=True
    )
    print(f"File verification command sent to {task.host.name}")
    print(verify_result.result)

# Nornir初期化
nr = InitNornir(config_file="config.yaml") # Nornir設定ファイル(inventories: {plugin: Simple, options: {host_file: "hosts.yaml"}} など)

# 特定の機器グループやホストに対してタスクを実行
# 例えば routers グループに対して実行する場合:
# nr.filter(group="routers").run(task=transfer_os_image)

# 全機器に対して実行する場合:
results = nr.run(task=transfer_os_image)

# 結果の確認(エラーハンドリング)
for host, result in results.items():
    if result.failed:
        print(f"--- {host} FAILED ---")
        print(result.exception)
    else:
        print(f"--- {host} SUCCESS ---")

コメント: ファイル転送コマンドやその後の確認コマンドは、機器のベンダーやOSによって大きく異なります。対応するコマンドを事前に確認し、スクリプト内で条件分岐させる必要があります。expect_string は、ファイル転送中に出力されるプロンプト(例: Destination filename?)に対応するために使用します。

ブートイメージ設定と再起動

次に、次回起動時に新しいOSイメージファイルを使用するように設定を変更し、機器を再起動します。設定変更には netmiko_send_config タスクを使用します。

from nornir import InitNornir
from nornir_netmiko.tasks import netmiko_send_config
from nornir_netmiko.tasks import netmiko_send_command
import time

def apply_os_patch_and_reboot(task):
    # ブートイメージ設定コマンド(Cisco IOS XEの例)
    # 注意: ベンダー・OSによりコマンドは異なる。
    # 設定投入前に既存のboot system設定を削除する必要がある場合も
    boot_commands = [
        f"boot system flash:{task.host['data']['os_image_file']}",
        "end",
        "write memory" # 設定保存
    ]

    print(f"Configuring boot image on {task.host.name}...")
    config_result = task.run(
        task=netmiko_send_config,
        config_commands=boot_commands,
        cmd_verify=True # 設定が正しく反映されたか検証(ベンダーによる)
    )
    print(f"Boot configuration sent to {task.host.name}")
    print(config_result.result)

    # 再起動コマンド(Cisco IOS XEの例)
    reboot_command = "reload"
    print(f"Rebooting {task.host.name}...")
    # 再起動コマンドはセッションが切断されるため、特殊な handling が必要
    # confirm=False は確認プロンプトを出さないオプション(機器による)
    reboot_result = task.run(
        task=netmiko_send_command,
        command_string=reboot_command,
        use_text=True,
        expect_string=r'Proceed with reload? \[confirm\]', # 再起動確認プロンプトを待つ
        strip_prompt=False, strip_command=False
    )
    print(reboot_result.result)

    # 再起動確認プロンプトに対してエンターキーを入力するなど応答する
    if 'Proceed with reload? [confirm]' in reboot_result.result:
         # 機器が再起動確認を求めた場合、確認を送信
        print(f"Sending confirmation to reboot {task.host.name}...")
        confirm_result = task.run(
             task=netmiko_send_command,
             command_string='\n', # エンターキーを送信
             expect_string=r'[#>]', # プロンプトに戻ることを期待
             strip_prompt=False, strip_command=False,
             read_timeout=10 # 短めのタイムアウトで試行
         )
        print(confirm_result.result)


# Nornir初期化など(上記 transfer_os_image の例を参照)
# ... Nornir initialization ...

# タスク実行
results = nr.run(task=apply_os_patch_and_reboot)

# 結果確認
for host, result in results.items():
    if result.failed:
        print(f"--- {host} FAILED ---")
        print(result.exception)
    else:
        print(f"--- {host} SUCCESS ---")

# 再起動後の機器が起動してSSH接続できるようになるまで待機
# 機器が多数ある場合は並列でポーリングするなどの工夫が必要
print("\nWaiting for devices to come back up...")
time.sleep(300) # 例として5分待機

コメント: 再起動処理は、自動化スクリプトにとって最もトリッキーな部分の一つです。再起動コマンド実行後にセッションが切断されるため、スクリプト側で機器が再びオンラインになるまで待機し、再接続を試みる処理が必要です。Nornirでは Nornir.run() の挙動を制御することで、再接続を自動で行うオプションもありますが、より堅牢にするためには、再接続処理を明示的に実装するか、別途ポーリングスクリプトを用意する方が良い場合があります。

適用後確認

OSバージョン、コンフィグ、状態などを確認します。NAPALMを使用すると、ベンダーに依存しない方法で多くの情報を取得できます。

from nornir import InitNornir
from nornir_napalm.tasks import napalm_get

def verify_os_version_and_state(task):
    # NAPALMでデバイスの情報を取得
    print(f"Getting facts from {task.host.name}...")
    facts_result = task.run(task=napalm_get, getters=["facts"])
    os_version = facts_result.result["facts"]["os_version"]
    print(f"{task.host.name}: OS Version is {os_version}")

    # 想定する新しいOSバージョンと一致するか確認
    expected_version = "Expected OS Version String" # ここに期待するバージョンを記述
    if expected_version not in os_version:
        print(f"WARNING: {task.host.name} - OS version mismatch. Expected '{expected_version}', got '{os_version}'")
        # エラーを記録または通知する処理

    # 適用前後のコンフィグや状態比較(応用)
    # 適用前に取得したバックアップと比較するなど
    print(f"Getting config from {task.host.name}...")
    config_result = task.run(task=napalm_get, getters=["config"])
    running_config = config_result.result["config"]["running"]
    # 以前取得したrunning_configと比較する処理
    # 例: difflib.unified_diff などを使用

# Nornir初期化など
# ...

# タスク実行
# nr.filter(...) or nr.run(...)

コメント: NAPALMで取得できる情報は getters パラメータで指定します (facts, config, interfaces, bgp_neighbors など)。適用前にも同様の情報を取得しておき、Diffを取ることで意図しない設定変更がないかを確認できます。

実践的な考慮点

OSパッチ適用のようなクリティカルな作業の自動化においては、以下の点を十分に考慮する必要があります。

まとめ

Pythonは、ネットワーク機器のOSパッチ適用という、従来手作業で行われることが多かったクリティカルな運用作業を自動化するための強力なツールとなります。Netmiko, Paramiko, Nornir, NAPALMといったライブラリを組み合わせることで、ファイル転送、CLIコマンド実行、状態確認といった一連のプロセスをスクリプト化できます。

自動化を成功させるためには、単にコマンドを実行するだけでなく、認証情報の安全な管理、堅牢なエラーハンドリング、明確なロールバック戦略、そして実行結果の記録とレポーティングといった実践的な考慮点が不可欠です。

これらの要素を組み合わせ、段階的に自動化の範囲を広げていくことで、ネットワーク機器のOSパッチ適用作業における運用負荷を軽減し、ヒューマンエラーのリスクを最小限に抑え、より安全で効率的なインフラ運用を実現することが可能になります。

この記事でご紹介したスクリプト例や手法が、皆様の現場でのネットワーク自動化推進の一助となれば幸いです。