1. はじめに
前回の記事で、自動化フレームワーク「Nonir」のセットアップ方法、NW機器への接続、showコマンド実行と出力結果のパース等を行いました。
Nornir3によるネットワーク自動化 ①セットアップ、showコマンド実行編
今回はその続きで、同じくCisco IOS/NX-OS機器に対して設定変更、設定保存、事後のConfig反映確認を行ってみました。
2. セットアップ
2-1. Nornir + Plugins
Netmikoで設定変更と保存を行うためにnornir_netmiko
プラグイン、Jinja2テンプレートからConfigを自動生成するためにnornir_jinja2
プラグインを使います。
前回インストールしていなかった後者を追加インストールします。
pip install nornir_jinja2
3. Inventory / Configファイル
前回と同じものを使います。
4. Tasks (Pythonコード) と実行結果
4-1. 例1: Configファイルからの設定変更
簡単な例として、以下のNTPサーバ設定ファイルを流し込んでみます。
ntp server 1.1.1.1 prefer
ntp server 2.2.2.2
from nornir import InitNornir
from nornir.core.task import Task, Result
from nornir_utils.plugins.functions import print_result
from nornir_netmiko.tasks import netmiko_send_config
# 初期化
nr = InitNornir(config_file="config.yaml")
# タスクを実行し、result変数に格納
result = nr.run(
# 実行結果に任意で名前を付けられる。指定しない場合はタスク名が使用される
name="configure ntp server",
# nornir_netmikoプラグイン内の関数を指定
task=netmiko_send_config,
# 設定ファイル(str型)
config_file="ntp_config.txt"
)
# 実行結果を表示
print_result(result)
実行結果
2台とも問題なく設定が行われました。複数回実行しても同じ結果だったため、Ansibleのような冪等性を担保する実装はされていないようです。
$ python nornir20.py
configure ntp server************************************************************
* iosvl2-0 ** changed : True ***************************************************
vvvv configure ntp server ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
iosvl2-0(config)#ntp server 1.1.1.1 prefer
iosvl2-0(config)#ntp server 2.2.2.2
iosvl2-0(config)#end
iosvl2-0#
^^^^ END configure ntp server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* nxos-0 ** changed : True *****************************************************
vvvv configure ntp server ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
nxos-0(config)# ntp server 1.1.1.1 prefer
nxos-0(config)# ntp server 2.2.2.2
nxos-0(config)# end
nxos-0#
^^^^ END configure ntp server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4-2. 例2: PythonコードによるConfig生成 + 設定変更
続いて、PythonコードでNTPサーバ設定を動的に生成し、設定変更を行ってみます。
タスクを定義する関数configure_ntp_server
の冒頭で、hostsファイルからリスト形式のNTPサーバアドレスを読み込み、1つ目の要素はprefer
オプションあり、2つ目以降の要素はオプションなしでConfigに変換しています。
NTPサーバアドレスはhostsファイルではなくdefaultsファイルのdata
キー内に定義していましたが、自動的にhostsファイルのdata
キーの値として認識されるようです。
from nornir import InitNornir
from nornir.core.task import Task, Result
from nornir_utils.plugins.functions import print_result
from nornir_netmiko.tasks import netmiko_send_config
def configure_ntp_server(task: Task) -> Result:
# NTPサーバ設定Configの生成
ntp_command = []
num = 0
for ip in nr.inventory.hosts[task.host.name]["ntp_server"]:
ntp_command.append(f"ntp server {ip}{' prefer' if not num else ''}")
num += 1
data = task.run(
# nornir_netmikoプラグイン内の設定変更用関数を指定
task=netmiko_send_config,
# 設定コマンド(list型)
config_commands=ntp_command
)
nr = InitNornir(config_file="config.yaml")
# 上記のカスタムタスクを実行し、結果をresultに格納
result = nr.run(
task=configure_ntp_server
)
# 実行結果を表示
print_result(result)
実行結果
例1と同様の結果になっています。
$ python nornir21.py
configure_ntp_server************************************************************
* iosvl2-0 ** changed : True ***************************************************
vvvv configure_ntp_server ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- netmiko_send_config ** changed : True ------------------------------------- INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
iosvl2-0(config)#ntp server 1.1.1.1 prefer
iosvl2-0(config)#ntp server 2.2.2.2
iosvl2-0(config)#end
iosvl2-0#
^^^^ END configure_ntp_server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* nxos-0 ** changed : True *****************************************************
vvvv configure_ntp_server ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- netmiko_send_config ** changed : True ------------------------------------- INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
nxos-0(config)# ntp server 1.1.1.1 prefer
nxos-0(config)# ntp server 2.2.2.2
nxos-0(config)# end
nxos-0#
^^^^ END configure_ntp_server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4-3. 例3: Jinja2によるConfig生成 + 設定変更 + 保存 + テスト
最後に、Jinja2でテンプレートファイルとNTPサーバアドレスをレンダリングしてConfigを動的に生成し、設定変更を行ってみます。その後設定保存と、投入したコマンドがshow runの中に含まれているか確認します。
タスクは以下の1~5で構成されています。
(1) NTPサーバ設定Configの生成
(2) NTPサーバ設定変更
(3) 設定保存
(4) 事後のConfig取得
(5) 事後ConfigにNTPコマンドが存在するか確認
(1)はnornir_jinja2
プラグイン、(2)~(4)はnornir_netmiko
プラグイン、(5)は自作したvalidate_config
を使っています。Pythonそのものを使っているので、カスタムのしやすさも魅力だと思います。
Jinja2テンプレートファイル
ntp server {{ host["ntp_server"][0] }} prefer
{% for ip in host["ntp_server"][1:] %}
ntp server {{ ip }}
{% endfor %}
from nornir import InitNornir
from nornir.core.task import Task, Result
from nornir_utils.plugins.functions import print_result
from nornir_netmiko.tasks import netmiko_send_command, netmiko_send_config, netmiko_save_config
from nornir_jinja2.plugins.tasks import template_file
# 事後のConfig内に、指定したコマンドが含まれているか判定
def validate_config(task: Task, intended_list: list, config: str) -> Result:
result = ""
for intended in intended_list:
try:
assert intended in config
result += f"Assertion Success: '{intended}' exists in config\n"
except AssertionError:
result += f"Assertion Failure: '{intended}' not exists in config\n"
return Result(host=task.host, result=result, changed=False)
def configure_ntp_server(task: Task) -> Result:
data1 = task.run(
# NTPサーバ設定Configの生成
name="generate ntp config",
# nornir_jinja2プラグイン内のJinja2テンプレートファイルからの設定変更用関数を指定
task=template_file,
# テンプレートファイル(str型)
template="ntp_config.j2",
path="./"
)
data2 = task.run(
# NTPサーバ設定変更
name="configure ntp server",
# nornir_netmikoプラグイン内の設定変更用関数を指定
task=netmiko_send_config,
# 設定コマンド(list型)。1つ目のタスクで生成された改行付き文字列を、リスト形式に変換したもの
config_commands=data1.result.splitlines()
)
data3 = task.run(
# 設定保存
name="save config",
# nornir_netmikoプラグイン内の設定保存用関数を指定
task=netmiko_save_config,
cmd="copy run start",
confirm="Destination filename",
confirm_response="\n"
)
data4 = task.run(
# 事後のConfig取得
name="run show command",
task=netmiko_send_command,
enable=True,
command_string="show run | inc ntp",
)
data5 = task.run(
# 事後ConfigにNTPコマンドが存在するか確認
name="confirm intended ntp commands exist",
task=validate_config,
intended_list=data1.result.splitlines(),
config=data4.result
)
nr = InitNornir(config_file="config.yaml")
# 上記のカスタムタスクを実行し、結果をresultに格納
result = nr.run(
task=configure_ntp_server
)
# 実行結果を表示
print_result(result)
実行結果
タスク1~5ともに問題なく完了し、最後でAssertion Success
と表示されています。
$ python nornir23.py
configure_ntp_server************************************************************
* iosvl2-0 ** changed : True ***************************************************
vvvv configure_ntp_server ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- generate ntp config ** changed : False ------------------------------------ INFO
ntp server 1.1.1.1 prefer
ntp server 2.2.2.2
---- configure ntp server ** changed : True ------------------------------------ INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
iosvl2-0(config)#ntp server 1.1.1.1 prefer
iosvl2-0(config)#ntp server 2.2.2.2
iosvl2-0(config)#end
iosvl2-0#
---- save config ** changed : True --------------------------------------------- INFO
copy run start
Destination filename [startup-config]?
Building configuration...
---- run show command ** changed : False --------------------------------------- INFO
ntp server 1.1.1.1 prefer
ntp server 2.2.2.2
---- confirm intended ntp commands exist ** changed : False -------------------- INFO
Assertion Success: 'ntp server 1.1.1.1 prefer' exists in config
Assertion Success: 'ntp server 2.2.2.2' exists in config
^^^^ END configure_ntp_server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* nxos-0 ** changed : True *****************************************************
vvvv configure_ntp_server ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- generate ntp config ** changed : False ------------------------------------ INFO
ntp server 1.1.1.1 prefer
ntp server 2.2.2.2
---- configure ntp server ** changed : True ------------------------------------ INFO
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
nxos-0(config)# ntp server 1.1.1.1 prefer
nxos-0(config)# ntp server 2.2.2.2
nxos-0(config)# end
nxos-0#
---- save config ** changed : True --------------------------------------------- INFO
copy run start
---- run show command ** changed : False --------------------------------------- INFO
ntp server 1.1.1.1 prefer
ntp server 2.2.2.2
---- confirm intended ntp commands exist ** changed : False -------------------- INFO
Assertion Success: 'ntp server 1.1.1.1 prefer' exists in config
Assertion Success: 'ntp server 2.2.2.2' exists in config
^^^^ END configure_ntp_server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
最後に
他の強力な自動化ツールであるAnsibleでは、冪等性が担保されていたり、独自のJinja2フィルターがあったりするため、同様の機能まで作りこむとなると大変かと思います。ネットワーク作業で、冪等性を気にする必要が無ければ、Nornirも有効なツールかと思います。
追加参考URL
- 公式サイト
GitHub - nornir_jinja2