Python
Network
junos
Router
IOS-XR

マルチベンダルータ制御APIライブラリ NAPALMを触ってみた

More than 1 year has passed since last update.

(追記)2016年12月24日に本記事の続編を書きました。そちらのほうがより詳しく記載してますので、ご興味あればみてください。

続・マルチベンダルータ制御APIライブラリ NAPALMを触ってみた


NAPALM概要

NAPALMというルータ制御APIライブラリが、NANOG64にて紹介されました。

https://www.nanog.org/meetings/abstract?id=2588

NAPALM (読み方は、日本人的には「ナパーム」でしょうか。NANOGでは「ネイパーム」と呼ばれていました)は、Spotify社が提供しているOSSのPythonライブラリであり、名前は「Network Automation and Programmability Abstraction Layer with Multivendor support」の略のようです。

ソースコードはgithubで公開されています。

https://github.com/spotify/napalm

NAPALMはその名の通り、下記の複数メーカの装置を統一化されたAPIにて制御することが可能です。今後さらに対応するルータOSが増えてくるかもしれません。

対応ルータOS


  • Arista製スイッチOSのEOS

  • Juniper製ルータOSのJUNOS

  • Cisco製ルータOSのIOS-XR

  • Fortinet製アプライアンスOSのFortiOS


NAPALMでできること

Githubのcommit logを見る限り 2015年3月頃から本格的な開発が始まっており、実装されている機能はコンフィグ設定部分にフォーカスされています。NAPALM自身では、現在のソフトウェアをversion0.12と位置付けているようです。(setup.pyに記載があります)

NANOG64発表資料では、NAPALMが持つ機能を下記のように紹介されています。


Supported Methods v0.1


  • load_replace_config


    • 全てのコンフィグの上書き



  • load_merge_config


    • 一部コンフィグのマージ



  • diff_config


    • 投入コンフィグと動作しているコンフィグの差分取得



  • discard


    • 投入コンフィグの廃棄



  • commit


    • 投入コンフィグのコミット



  • rollback


    • 前回コミットした状態へのロールバック




Supported Methods v0.2(beta)


  • get_facts


    • 機器の基本情報の取得



  • get_interfaces


    • インタフェースごとの情報の取得



  • get_bgp_neighbors


    • BGPセッションの情報取得



  • get_lldp_neighbors


    • LLDPネイバーの状態取得



2015年6月7日時点では、v0.1の部分のみ実装されているようです。

これらに加えて、構成管理ツールであるAnsibleから呼び出すための拡張モジュールが提供されており、NANOG64ではAnsibleを活用したコンフィグをルータに投入/commitするデモが行われてました。

Ansible Modules


  • Module to push configurations

  • Module to get facts

当日の発表とデモの風景はNANOG Youtubeチャンネルで公開されています。


NAPALMを使ってみた

napalmの使い方を理解するために公式ドキュメントのチュートリアルを眺めながら進めました。

NAPALMのインストールは簡単です。

pip install napalm 

pipを使ったことがない方はこちらの記事を参考にpipをインストールしてください。

Pythonで一番最初に入れるべきパッケージ setuptools と pip

http://www.lifewithpython.com/2012/11/Python-package-setuptools-pip.html


IOS-XRで試してみた

まずはcisco IOS-XRで試してみます。

NAPALMで使っているpyIOSXR( https://github.com/fooelisa/pyiosxr )というモジュールでは、CISCO XML APIを利用してIOS-XRの設定を実現しています。

そのためIOS-XRが動くルータでXML入力を許可するために、事前に以下のコンフィグを設定しておく必要があります。タイマー値は適当ですので、必要に応じて変更してください。

xml agent tty

session timeout 30
!

公式ドキュメントのチュートリアルを参考にして、下記のようなPythonアプリケーションを作ってみました。

アプリケーションの流れとしては、ルータホスト名を'router1_changed_by_NAPALM'という名前に変更するコンフィグファイル(change_hostname_configIOSXR.txt)をルータに設定投入し、コンフィグ差分を確認して、問題がなければcommit、もしくはdiscardする流れになっています。

一つ一つ正常に動作しているか途中経過を確認したかったので、見栄えは悪いですがprint文多めにしています。


run_napalm.py

#! /usr/bin/env python

from napalm import get_network_driver

driver = get_network_driver('IOSXR')
print 'Step.1 Create ios-xr instance : OK'

device = driver('192.168.0.1', 'test_user', 'test_passwd')
print 'Step.2 Set router information : OK'

device.open()
print 'Step.3 Open session : OK'

device.load_merge_candidate(filename='./change_hostname_configIOSXR.txt')
print 'Step.4 load_merge_candidate : OK'

print '### CHECK CANDIDATE CONFIG ###'
print device.compare_config()
print '### END CONFIG###'
print 'Step.5 Compare_config : OK'

print 'Do you commit? y/n'
choice = raw_input().lower()
if choice == 'y':
device.commit_config()
print 'Step.6 commit_config : OK'
elif choice == 'n':
device.discard_config()
print 'Step.6 Discard_config : OK'
else:
print 'Please input y or n. Discard candidate config'
device.discard_config()
print 'Step.6 Discard_config : OK'

device.close()
print 'Step.7 Close session : OK'

print 'Successful !!'



change_hostname_configIOSXR.txt

hostname router1_changed_by_NAPALM


まず、上記のツールを実行する前に、IOS-XRルータのコンフィグの状態をルータ上で確認します。

RP/0/RSP0/CPU0:router1#show running-config

Sun Jun 7 10:53:33.157 JST
Building configuration...
!! IOS XR Configuration #####
!! Last configuration change at Sun Jun 7 10:42:57 2015 by test_user
!
hostname router1
clock timezone JST 9
logging trap debugging
logging console debugging
...
...
...

では次に、作成したツール(run_napalm.py)を実行してみます。実行すると以下のように結果が出力されます。

$ python run_napalm.py

Step.1 Create ios-xr instance : OK
Step.2 Set router information : OK
Step.3 Open session : OK
Step.4 load_merge_candidate : OK
### CHECK CANDIDATE CONFIG ###
---
+++
@@ -3 +3 @@
-hostname router1
+hostname router1_changed_by_NAPALM
@@ -280,0 +281 @@
+!

### END CONFIG###
Step.5 Compare_config : OK
Do you commit? y/n
y
Step.6 commit_config : OK
Step.7 Close session : OK
Successful !!

ツール実行後、ルータで実際に設定が反映されているか確認してみます。

RP/0/RSP0/CPU0:router1_changed_by_NAPALM#show running-config

Sun Jun 7 10:59:42.313 JST
Building configuration...
!! IOS XR Configuration ######
!! Last configuration change at Sun Jun 7 10:56:07 2015 by test_user!
hostname router1_changed_by_NAPALM
clock timezone JST 9
logging trap debugging
logging console debugging
...
...
...

正しくIOS-XRルータのホスト名を変更できたようです。

NAPALMで用意された関数を使うことで、比較的簡単にルータ設定のアプリケーションを書くことができました。


JUNOSで試してみた

次は、IOS-XRで使ったプログラムとほぼ同じスクリプトを使って、JUNOSルータのホスト名を変更してみます。

実施したアプリケーションのソースコードです。


run_napalm.py


#! /usr/bin/env python

from napalm import get_network_driver

driver = get_network_driver('JUNOS')
print 'Step.1 Create junos instance : OK'

device = driver('192.168.0.2', 'test_user', 'test_passwd')
print 'Step.2 Set router information : OK'

device.open()
print 'Step.3 Open session : OK'

device.load_merge_candidate(filename='./change_hostname_configJUNOS.txt')
print 'Step.4 load_merge_candidate : OK'

print '### CHECK CANDIDATE CONFIG ###'
print device.compare_config()
print '### END CONFIG###'
print 'Step.5 Compare_config : OK'

print 'Do you commit? y/n'
choice = raw_input().lower()
if choice == 'y':
device.commit_config()
print 'Step.6 commit_config : OK'
elif choice == 'n':
device.discard_config()
print 'Step.6 Discard_config : OK'
else:
print 'Please input y or n. Discard candidate config'
device.discard_config()
print 'Step.6 Discard_config : OK'

device.close()
print 'Step.7 Close session : OK'

print 'Successful !!'


実行結果はこちらです。

$ python run_napalm.py

Step.1 Create junos instance : OK
Step.2 Set router information : OK
No handlers could be found for logger "paramiko.hostkeys"
Traceback (most recent call last):
File "./run_napalm.py", line 14, in <module>
device.open()
File "/usr/lib/python2.7/site-packages/napalm/junos.py", line 32, in open
self.device.open()
File "/usr/lib/python2.7/site-packages/jnpr/junos/device.py", line 433, in open
raise EzErrors.ConnectTimeoutError(self)
jnpr.junos.exception.ConnectTimeoutError: ConnectTimeoutError(192.168.0.2)

あれ、失敗してしまいました。。。

SSHモジュールであるparamikoのログイン認証の部分で失敗しているようです。こちらはJUNOSルータの設定不足(netconfの部分?)か、プログラムのbugかも知れないので、引き続き調査してみます。

もしJUNOSルータに対して、うまく動作できた方がいればご教授いただきたいです。


所感

実装が始まったばかりのNAPALMですが、機種やメーカを意識せずにルータを操作するアプリケーションが書けるので、ツール開発が非常にやりやすくなりました。まだコンフィグ設定機能しか実装されていないものの、複数のルータに対して同じ設定を入れるような場面では、現段階の実装でも十分に使えそうです。

ただし、現時点では実装途中の機能やbugも含まれそうなので、利用する際は十分な検証を行ってから実施してください。

NAPALM自身のソースコードを覗いた感じでは、プログラム的に難しい処理をしているわけではなく、基本部分(base.py)でも100行程度であり、個人レベルでも十分に開発に参加できそうな感じでした。

githubのソースコードを見ていて驚いたのが、このNAPALMに限らず、中で呼び出しているpyIOSXRやpyEOS、pyFGの大部分を、AutherであるDavid Barroso、Elisa Jasinskaの両氏がほぼ単独で実装していることでした。「メーカが用意しないなら自分たち自身でAPIを作ってしまおう!」という意気込みがこのプロジェクトから感じられました。