(追記)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文多めにしています。
#! /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 !!'
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ルータのホスト名を変更してみます。
実施したアプリケーションのソースコードです。
#! /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を作ってしまおう!」という意気込みがこのプロジェクトから感じられました。