てくなべ (tekunabe)

ansible / network / automation / StackStorm

[nornir] Python 製自動化フレームワーク「nornir」かんたんチュートリアル(Ansibleと比較しながら)


※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 系ではコネクションパラメータ名の方法が異なりますので、本記事の最後記事の最後で補足します。

github.com

https://nornir.readthedocs.io/en/stable/index.html

  • 環境
    • nornir 2.0.0
    • Python 3.6.5
    • Ansible 2.7.5 (比較用)
    • Centos 7.5.1804

Ansible との比較

Ansible や Salt は構成の定義を YAMLDSLという見方もできると思います)で記述します。 一方 nornir は純粋に Python のライブラリなので、実現したいことを Python でコーディングします。 Ansible で Playbook を書いていて、だんだん複雑になり「コードで書きたいな・・」と思ったときに、代替手段になるかもしれません。

netmiko や NAPALM との比較

ネットワーク機器への自動化といえば、netmikoNAPALMといった、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 アドレスを定義します。

vsrx1:                   # (nornir管理上の)ホスト名
  groups:                # 所属するグループの定義
    - junos              # グループ名
  hostname: 172.16.0.1   # (実際に接続するための)ホスト名または IP アドレス
vsrx2:
  groups:
    - junos
  hostname: 172.16.0.2

続いて、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 matrixDriver Name に記載があるもの。

NAPALM 2.3.3 現在は以下(クリックで表示)

  • eos
  • junos
  • iosxr
  • nxos
  • nxos_ssh
  • ios
netmiko を利用する場合

netmiko/ssh_dispatcher.pyCLASS_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.yamlgroups.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 コマンドの結果が表示されました。

以下のような色の表示になります。

f:id:akira6592:20181218171119p:plain
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 が候補になるかもしれません。


■ 参考


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