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

  • 32
    いいね
  • 3
    コメント

(追記)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を作ってしまおう!」という意気込みがこのプロジェクトから感じられました。