※2018/12/18 更新: nornir 2.0.0 リリース に伴い、全面的に 2.0.0 対応に更新しました。
■ nornir とは
nornir は、Python 製の新しい自動化フレームワークです。 netmiko や NAPALM も取り込んでいるため、ネットワーク機器にも対応しています。 この記事では、ネットワーク機器を対象としたチュートリアルをご紹介します。
本チュートリアルは、2018/12/18 現在 の最新バージョンである [2.0.0] を対象にしています。 nornir 1.x 系と 2.x 系ではコネクションパラメータ名の方法が異なりますので、本記事の最後記事の最後で補足します。
https://nornir.readthedocs.io/en/stable/index.html
Ansible との比較
Ansible や Salt は構成の定義を YAML(DSLという見方もできると思います)で記述します。 一方 nornir は純粋に Python のライブラリなので、実現したいことを Python でコーディングします。 Ansible で Playbook を書いていて、だんだん複雑になり「コードで書きたいな・・」と思ったときに、代替手段になるかもしれません。
netmiko や NAPALM との比較
ネットワーク機器への自動化といえば、netmiko や NAPALMといった、Python ライブラリもあります。 nornir は これらのライブラリの機能に、インベントリや変数管理の仕組みをつけたフレームワークのようなものです。
requirements.txt を確認すると分かるように、nornir をインストールすると、netmiko や NAPALM もインストールされます。
■ インストールは pip install nornir
nornir のインストール手順は以下の通りです。
pip install nornir
必要に応じて virtualenv
などを利用して、環境を分けてください。
なお、Python 2.7 もまだサポートされていますが、推奨は 3.6 とされています。
■ チュートリアル: Junos の 2台 の show version
結果を表示
インストールができたところで、Juniper Junos の 2台の show version
コマンド結果を表示するチュートリアルをはじめます。実際にネットワーク機器に接続する部には NAPALM を使用します。
説明のために、同じことを Ansible(2.7.5) で実現する場合と比較しながら説明します。
インベントリと変数定義の準備
対象ホストを定義するインベントリと、それらに適用される変数定義のファイルを準備します。
nornir の場合
hosts.yaml
(今回のコードの場合、ファイル名は固定)で、ホストの名前、所属させるグループ、実際に接続する IP アドレスを定義します。
- hosts.yaml
vsrx1: # (nornir管理上の)ホスト名 groups: # 所属するグループの定義 - junos # グループ名 hostname: 172.16.0.1 # (実際に接続するための)ホスト名または IP アドレス vsrx2: groups: - junos hostname: 172.16.0.2
続いて、groups.yaml
(今回のコードの場合、ファイル名は固定)で、グループの名前、と利用する変数(ログイン情報など)を定義します。
- groups.yaml
junos: # グループ名 username: root # ログインユーザー名 password: pasword9999 # ログインパスワード platform: junos # プラットフォーム名
hosts.yaml
内の groups
で指定した junos
が、groups.yml
内の junos:
に対応します。
プラットフォーム名の junos
は、対象のネットワーク機器によって変更します。もし Cisco IOS であれば ios
を指定します。
補足: 対象に指定できるプラットフォームについて
指定できるプラットフォームの一覧は nornir のドキュメントには見当たりませんでした。 実際のネットワーク機器への接続部分に、NAPALM 利用するか netmiko を利用するかによって異なります。
NAPALM を利用する場合(本チュートリアルはこちら)
NAPALM ドキュメントのGeneral support matrixの Driver Name
に記載があるもの。
NAPALM 2.3.3 現在は以下(クリックで表示)
netmiko を利用する場合
netmiko/ssh_dispatcher.py の CLASS_MAPPER
で定義されるもの。
netmiko 2.3.0 現在は以下( 末尾に
_ssh
を付けた形も可)(クリックで表示)
- a10
- accedian
- alcatel_aos
- alcatel_sros
- apresia_aeos
- arista_eos
- aruba_os
- avaya_ers
- avaya_vsp
- brocade_fastiron
- brocade_netiron
- brocade_nos
- brocade_vdx
- brocade_vyos
- calix_b6
- checkpoint_gaia
- ciena_saos
- cisco_asa
- cisco_ios
- cisco_nxos
- cisco_s300
- cisco_tp
- cisco_wlc
- cisco_xe
- cisco_xr
- coriant
- dell_dnos9
- dell_force10
- dell_isilon
- dell_os10
- dell_os6
- dell_os9
- dell_powerconnect
- eltex
- enterasys
- extreme
- extreme_ers
- extreme_exos
- extreme_netiron
- extreme_nos
- extreme_slx
- extreme_vdx
- extreme_vsp
- extreme_wing
- f5_linux
- f5_ltm
- f5_tmsh
- fortinet
- generic_termserver
- hp_comware
- hp_procurve
- huawei
- huawei_vrpv8
- ipinfusion_ocnos
- juniper
- juniper_junos
- linux
- mellanox
- mrv_optiswitch
- netapp_cdot
- netscaler
- ovs_linux
- paloalto_panos
- pluribus
- quanta_mesh
- rad_etx
- ruckus_fastiron
- ubiquiti_edge
- ubiquiti_edgeswitch
- vyatta_vyos
- vyos
なお、私が試した限り netmiko にないプラットフォーム名 ios
でも netmiko を利用できました。plugins/connections/netmiko.py にある以下の変換表によって変換されて利用できたようです。
napalm_to_netmiko_map = { "ios": "cisco_ios", "nxos": "cisco_nxos", "eos": "arista_eos", "junos": "juniper_junos", "iosxr": "cisco_xr", }
Ansible の場合
Ansible の場合は、以下のようなインベントリファイルと、グループ変数定義ファイルを用意します。
- inventory.ini
[junos] vsrx1 ansible_host=172.16.0.1 vsrx2 ansible_host=172.16.0.2
- group_vars/junos.yaml
--- ansible_network_os: junos ansible_connection: netconf # 今回は network_cli でも可 ansible_user: root ansible_password: pasword9999
実行ファイルの準備
nornir の場合
hosts.yaml
、groups.yaml
と同じディレクトに、以下の Python スクリプトを作成します。
show_version.py
from nornir import InitNornir from nornir.plugins.functions.text import print_result from nornir.plugins.tasks.networking import napalm_cli # オブジェクトの初期化 nr = InitNornir() # 実行 results = nr.run( # コマンドを直接実行するタスク napalm_cli を呼び出して、コマンドは show version を指定 task=napalm_cli, commands=["show version"] ) # nornir 用の出力関数で結果を出力 print_result(results)
今回は、何も指定していませんが、InitNorir
で初期化時に、パラメータを渡すことによって、ホストファイル名の指定などの設定ができます。詳細は API ドキュメントを参照してください。
補足: norinir + netmiko を利用する場合
前述の例では、実際のネットワーク機器への接続部分に NAPALM を使用しましたが、同様の処理は netmiko でもできます。 netmiko を利用する場合のサンプルは以下の通りです。
show_version_netmiko.py
from nornir import InitNornir from nornir.plugins.functions.text import print_result from nornir.plugins.tasks.networking import netmiko_send_command # netmiko # オブジェクトの初期化 nr = InitNornir() # 実行 results = nr.run( # コマンドを直接実行するタスク netmiko_send_command を呼び出して、コマンドは show version を指定 task=netmiko_send_command, command_string="show version" # リストではなく文字列を指定 ) # nornir 用の出力関数で結果を出力 print_result(results)
Ansible の場合
以下の Playbook を作成します。
show_version.yml
- hosts: all gather_facts: no tasks: - name: show version junos_command: commands: - show version register: result - name: debug version debug: msg: "{{ result.stdout_lines[0] }}"
実行
nornir の場合
python
コマンドで、先ほど作成したスクリプトを実行します。
$ python test.py napalm_cli********************************************************************** * vsrx1 ** changed : False ***************************************************** vvvv napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO { u'show version': u'\nHostname: vsrx1\nModel: firefly-perimeter\nJUNOS Software Release [12.1X47-D15.4]\n'} ^^^^ END napalm_cli ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * vsrx2 ** changed : False ***************************************************** vvvv napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO { u'show version': u'\nHostname: vsrx2\nModel: firefly-perimeter\nJUNOS Software Release [12.1X47-D15.4]\n'} ^^^^ END napalm_cli ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nornir を利用したコードで、無事に show version
コマンドの結果が表示されました。
以下のような色の表示になります。
Ansible の場合
$ ansible-playbook -i inventory.ini show_versoin.yml PLAY [all] ******************************************************************* TASK [show version] ********************************************************** ok: [vsrx1] ok: [vsrx2] TASK [debug version] ********************************************************* ok: [vsrx1] => { "msg": [ "Hostname: vsrx1", "Model: firefly-perimeter", "JUNOS Software Release [12.1X47-D15.4]" ] } ok: [vsrx2] => { "msg": [ "Hostname: vsrx2", "Model: firefly-perimeter", "JUNOS Software Release [12.1X47-D15.4]" ] } PLAY RECAP ******************************************************************* vsrx1 : ok=2 changed=0 unreachable=0 failed=0 vsrx2 : ok=2 changed=0 unreachable=0 failed=0
こちらも無事に show version
コマンドの結果が表示されました。
■ まとめ
今回は、簡単な show コマンド実行するだけのサンプルをご紹介しました。 他にも、設定系コマンドや、show コマンドの結果をパースして表示する機能などもあります。インベントリについても、今回は定義された全ホストに接続しましたが、フィルターする機能もあります。
「コードで処理を書きたい。でも Ansible のようなインベントリや変数管理の仕組みは欲しい。」という場合に、nornir が候補になるかもしれません。
■ 参考
- Python for Network Engineers | Articles
- Welcome to nornir’s documentation! — nornir 0.0.1 documentation
- 公式チュートリアル
Nornir - Python automation framework [Part 16] Network Programmability Stream
補足: nornir 1.x と 2.x の違い
nornir 1.x 系と 2.x 系(2.0.0 は 2018/12 リリース)では、コネクションパラメータ名などが異なります。
コネクションパラメータ名
1.x | 2.x | 補足 |
---|---|---|
nornir_host |
hostname |
|
nornir_nos |
platform |
|
nornir_ssh_port |
port |
本チュートリアル未使用 |
nornir_network_api_port |
port |
本チュートリアル未使用 |
nornir_username |
username |
|
nornir_password |
password |
InitNornir
のインポート方法
- 1.x
from nornir.core import InitNornir
- 2.x
from nornir import InitNornir
nornir 1.x 系と 2.x 系へのアップグレード方法の詳細は以下のページを参照してください。 https://nornir.readthedocs.io/en/latest/upgrading/1_to_2.html