JunosのOn-box Pythonを使ってみる #1 Op Script

# 概要

[NetOpsCoding Advent Calendar 2016](http://qiita.com/advent-calendar/2016/netopscoding)の11日目の記事です。

今回は、Junos 16.1から搭載されたOn-box Pythonの使い方を紹介してみたいと思います。

# Junoscriptについて

Junoscriptとは、Junosルータ上で動作するスクリプト環境で、動作するタイミングによってOp Script(任意のタイミングで動作)とCommit Script(設定のコミット時に動作)、Event Script(何らかのイベントに応じて動作)の3つが存在します。
これまでは、Junoscriptを使用するためには、XSLTまたはSLAXによる少々独特なスクリプトの記述が必要でしたが、Junos 16.1からはこれらをPythonにて記述する事が出来るようになりました。
On-box Pythonでは、以前から存在するPyEZベースの簡潔な操作をベースに、これまでJunoscriptで可能だった機能を拡張したものとなっています。

今回はまずさわりという事で、Op Scriptを記述して試してみたいと思います。

詳細は、[公式ドキュメント](https://www.juniper.net/documentation/en_US/junos16.1/topics/concept/junos-script-automation-python-scripts-overview.html)を参照頂ければと思います。

# 環境

今回は以下のような環境で試しています。

* Juniper vMX 16.1R3.10

# 設定

On-box Pythonは、初期状態では有効になっていません。有効にするためには、以下の設定を投入する必要があります。

```set system scripts language python```

これにより、op/event/commit scriptにPythonで記述したスクリプトが指定できるようになります。

また、Junoscriptでは、セキュリティ上、実行したいスクリプトはコンフィグ内にて指定しておく必要がありますので、任意のタイミングで実行できるopスクリプトであっても、以下のような設定が必要となります。

```set system scripts op file test.py```

ここで指定するスクリプトファイルは、```/var/db/scripts/op/```に保存しておく必要があります。

# Hello, world!

事前準備が整いましたので、早速適当なスクリプトを書いてみたいと思います。
まずは定番ということで、特に意味はありませんが、Hello worldを書いて動かしてみましょう。

```/var/db/scripts/op/``` にtest.pyという名前で以下のスクリプトを配置します。

```test.py
def main():
    print "Hello, world!"

if __name__ == "__main__":
    main()
```

前述したとおり、スクリプトを実行するためには、スクリプトのファイル名をコンフィグ内に定義しておく必要がありますので、上記の例の通り指定し、Commitしておきます。

設定及びスクリプトの内容が正しければ、以下のような形でスクリプトが実行できるはずです。

```
root@vmx1> op test.py
Hello, world!
```

# 情報を取得してみる

さて、Hello worldを実行しても何の意味もありませんので、もう少し実践的な内容を試してみましょう。
On-box Pythonでは、PyEZ(py-junos-eznc)を使用することができますので、これを使って適当な情報を取得して表示してみます。

たとえば、get-interface-information RPCを実行し、インターフェイス名を列挙するコードを書いてみましょう。

```test.py
from jnpr.junos import Device

def main():
    dev = Device()
    dev.open()

    interfaces = dev.rpc.get_interface_information(terse=True)

    for ifd in interfaces.getiterator("physical-interface"):
        print ifd.find("name").text.strip()

if __name__ == "__main__":
    main()
```

非常にシンプルなコードですね。 結果は以下のようになります。

```
root@vmx1> op test.py
ge-0/0/0
lc-0/0/0
pfe-0/0/0
pfh-0/0/0
ge-0/0/1
ge-0/0/2
ge-0/0/3
ge-0/0/4
ge-0/0/5
ge-0/0/6
ge-0/0/7
ge-0/0/8
ge-0/0/9
cbp0
demux0
dsc
em1
esi
fxp0
gre
ipip
irb
jsrv
lo0
lsi
mtun
pimd
pime
pip0
pp0
rbeb
tap
vtep
```

# 設定を変更してみる

続いて、設定の変更も試してみましょう。こちらもPyEZベースで行えるため、非常に簡単です。

ここでは例として、ge-0/0/0というインターフェイスを無効(disable)にするスクリプトを書いてみます。

```test.py
from jnpr.junos import Device
from jnpr.junos.utils.config import Config

def main():
    dev = Device()
    dev.open()
    dev.bind(cu=Config)

    config = "set interfaces ge-0/0/0 disable"

    dev.cu.lock()

    dev.cu.load(config, format="set", merge=True)

    dev.cu.commit()
    dev.cu.unlock()

    dev.close()


if __name__ == "__main__":
    main()
```

結果は以下のような形になります。

```
root@vmx1> show configuration interfaces ge-0/0/0 | display set
set interfaces ge-0/0/0 vlan-tagging
set interfaces ge-0/0/0 unit 1001 vlan-id 1001
set interfaces ge-0/0/0 unit 1001 family inet address 10.0.1.1/24

root@vmx1> op test.py

root@vmx1> show configuration interfaces ge-0/0/0 | display set
set interfaces ge-0/0/0 disable
set interfaces ge-0/0/0 vlan-tagging
set interfaces ge-0/0/0 unit 1001 vlan-id 1001
set interfaces ge-0/0/0 unit 1001 family inet address 10.0.1.1/24
```

ge-0/0/0の無効化の設定が投入されている事が分かるかと思います。

# 最後に

こういった形で、これまでサーバ上にてPyEZで記述していたスクリプトを、機器の上でも動作させることができるようになる、というのが、一つのOn-box Pythonの使用例となります。

しかしながら、On-box Pythonは上述した通り、これまでのJunoscriptを置き換える事が出来るものですので、本当の力はCommit Scriptや、Event Scriptを記述する言語として使用することで発揮されてきます。

[次回](http://qiita.com/kazubu/items/6d5c94cf32436c4d228f)は、Commit ScriptやEvent Scriptでの例をご紹介していきたいと思います。