Juniper JUNOS PyEz (python library)を試すメモ 2  ~PyEzによる情報取得~

[前回](http://qiita.com/hiromiarts/items/aade90a161acd63bc8ed)PyEzの環境構築ができたため、今回は実際にJUNOSの情報取得を試してみる。

PyEzを使った情報取得方法はいくつかあるが、今回はこの三つを試してみました。

 1. 事前に定義されている簡単に基本的な情報を取得できるfactsの活用
 2. YAMLファイルで定義された内容を取得できるTable and Viewの活用
 3. RPC(remote procedure calls)によるJUNOS showコマンドと同等の確認


#1.JUNOS情報取得(facts)

まずは、非常にシンプルだが、PyEzのHello worldとして、サーバーからJUNOSにコネクションを張り、factsにより基本的な情報(hostname,version情報など)を取得してみる。
factsは、NETCONFセッション確立時にJUNOSから収集した基本的な情報を表示する。
概要は[Tech Library](https://www.juniper.net/techpubs/en_US/junos-pyez1.2/topics/task/program/junos-pyez-program-device-connecting.html)に動作サンプルの動画もあるが、詳細は[GitHub](https://github.com/Juniper/py-junos-eznc)で確認可能。

``` 
#JUNOSと接続するためにDeviceモジュールをインポート
>>> From juniper. Junos import Device 
#デバイス情報を定義
>>> dev=Device(host='10.0.0.243', user="xxx", password="xxx", port='22')
#netconf over sshでJUNOSに接続
>>> Dev. open ()        
Device(1.1.1.1)
#factsにより基本情報表示
>>> print dev.facts　
{'domain': None, 'hostname': 'vSRX-1', 'ifd_style': 'CLASSIC', 'version_info': junos.version_info(major=(15, 1), type=X, minor=(49, 'D', 50), build=3), '2RE': False, 'serial number': 'xxxxx', 'fqdn': 'vSRX-1', 'switch_style': 'NONE', 'version': '15.1X49-xxx', 'HOME': '/var/home/vsrx', 'srx_cluster': False, 'model': 'VSRX', 'RE0': {'status': 'Testing', 'last_reboot_reason': '0x10: Misc hardware reason ', 'model': 'VSRX RE', 'up_time': '44 minutes'}, 'vc_capable': False, 'personality': 'UNKNOWN'}
#factsによりversion情報だけ表示
>>> dev.facts['version']
'15.1X49-xxx'
>>> dev.facts['hostname']
'vSRX-1‘

dev.close()
>>> quit()
``` 

factsを使ってOSのバージョン情報を取得してテキストに書き出すサンプル

``` 
from jnpr.junos import Device
from datetime import datetime

mydeviceslist=["1.1.1.1"]
f=open("my_devices_inventory.txt", "a")
f.write(str(datetime.now()) + '\n')
for item in mydeviceslist:
        dev=Device(host=item, user="xxx", password="xxx",port='22')
        dev.open()
        dev.close()
        print ("the device "+ dev.facts["hostname"]+ " is a " + dev.facts['model
'] + " running " + dev.facts["version"])
        f.write ( "the device "+ dev.facts["hostname"]+ " is a " + dev.facts['mo
del'] + " running " + dev.facts["version"] + "\n")
f.close()
``` 

実行結果
```
$ python print_facts.py
the device vSRX-1 is a VSRX running 15.1X49-xxx
[ec2-user@ip-10-0-0-47 facts]$  more　my_devices_inventory.txt
2016-08-22 08:01:29.396263 
the device vSRX_AWS-1 is a VSRX running 15.1X49-xxx
``` 




#2.JUNOS情報取得(Table and view)
jnpr.junos.opモジュールを使い、YAMLで定義されたTable and Viewにより各情報の取得ができる。
現在のopモジュールとしては、[ドキュメント](https://www.juniper.net/techpubs/en_US/junos-pyez1.0/topics/concept/junos-pyez-tables-and-views-overview.html)にあるようにarp, interface情報など基本的な情報が取得可能。
例として、[ArpTableメソッド](https://github.com/Juniper/py-junos-eznc/blob/master/lib/jnpr/junos/op/arp.yml)を使い、arp情報を取得してみる。

```  
>>> from jnpr.junos.op.arp import ArpTable
>>> arp1=ArpTable(dev)
>>> arp1.get() 
ArpTable:10.0.0.243: 3 items
#keyの一覧取得
>>> arp1.keys() 　　
['0a:de:e9:03:15:3f', '0a:ca:89:ec:9a:51', '0a:93:06:42:03:c5']
#valuesの一覧取得
>>> arp1.values() 　　
[[('interface_name', 'fxp0.0'), ('ip_address', '10.0.0.1'), ('mac_address', '0a:de:e9:03:15:3f')], [('interface_name', 'fxp0.0'), ('ip_address', '10.0.0.47'), ('mac_address', '0a:ca:89:ec:9a:51')], [('interface_name', 'ge-0/0/0.0'), ('ip_address', '10.0.1.1'), ('mac_address', '0a:93:06:42:03:c5')]]]
```  
 
[RouteTableメソッド](https://github.com/Juniper/py-junos-eznc/blob/master/lib/jnpr/junos/op/routes.yml)を利用して、ルーティング情報とデフォルトゲートウェイのテーブル情報を表示するサンプル

```  
from jnpr.junos import Device
from jnpr.junos.op.routes import RouteTable

dev = Device(host='10.0.0.243', user='xxx', password='xxx', port='22', gathe
r_facts=False)
dev.open()

tbl = RouteTable(dev)
tbl.get()

#get values and keys
for key, value in tbl.items():
    print "key:%s,\t value:%s" %(key, value)

##print only GW information
print '##this is default gateway'

gw = RouteTable(dev)
gw.get('0.0.0.0')
print gw
for item in gw:
    print 'protocol:', item.protocol
    print 'age:', item.age
    print 'via:', item.via
    print

dev.close()
```  

実行結果

```  
key:0.0.0.0/0,   value:[('nexthop', '10.0.0.1'), ('age', 177947), ('via', 'fxp0.0'), ('protocol', 'Static')]
key:10.0.0.0/24,         value:[('nexthop', None), ('age', 177947), ('via', 'fxp0.0'), ('protocol', 'Direct')]
key:10.0.0.243/32,       value:[('nexthop', None), ('age', 181163), ('via', 'fxp0.0'), ('protocol', 'Local')]
key:10.0.1.0/24,         value:[('nexthop', None), ('age', 181145), ('via', 'ge-0/0/0.0'), ('protocol', 'Direct')]
key:10.0.1.68/32,        value:[('nexthop', None), ('age', 181146), ('via', 'ge-0/0/0.0'), ('protocol', 'Local')]
key:10.0.2.98/32,        value:[('nexthop', None), ('age', 181144), ('via', 'ge-0/0/1.0'), ('protocol', 'Direct')]
key:10.0.3.85/32,        value:[('nexthop', None), ('age', 181144), ('via', 'ge-0/0/2.0'), ('protocol', 'Direct')]
key:192.168.0.1/32,      value:[('nexthop', None), ('age', 181162), ('via', 'lo0.0'), ('protocol', 'Direct')]
##this is default gateway
RouteTable:10.0.0.243: 1 items
protocol: Static
age: 177947
via: fxp0.0
```  

YAMLファイルを自分で定義して、Table and Viewを取得することもできる。
Gitに落ちてたサンプルとして、例えば[こんな](https://github.com/vnitinv/pyez-examples/blob/master/9_user_defined_table.py)感じ。


#3.JUNOS情報取得(RPC、showコマンド)
最後に、[RPCを使い](https://www.juniper.net/techpubs/en_US/junos-pyez1.2/topics/task/program/junos-pyez-rpcs-executing.html)CLIのshowコマンドと同等の情報を取得してみる。

・showコマンドとRPCのマッピング

JUNOS XML APIは、JUNOSのコンフィグやオペレーションモードのコマンドをXMLで表したものだが、
RPCでリクエストすることで、XMLのレスポンスを得ることができる。
PyEzでは、RPCを実行することになるが、CLIのコマンドとRPCは、マッピングできるため、使いたいCLIをRPCとして使うことになる。

そのためには、どのCLIがどのRPCなのかを確認する必要があるが、方法として、2つ紹介する。
 1. JUNOSの実機でshowコマンドで確認
    使いたいshowコマンドのあとに| display xml rpcで確認する。例えばshow interfaceの場合、

```
> show interfaces  | display xml rpc
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1X49/junos">
    <rpc>
        <get-interface-information>
        </get-interface-information>
    </rpc>
    <cli>
        <banner></banner>
    </cli>
</rpc-reply>
```

2.PyEzのdisplay_xml_rpc()メソッドで確認
　dev.open()でJUNOSと接続後、dev.display_xml_rpcメソッドで使用したいshowコマンドを指定し確認。
 
```
>>> print dev.display_xml_rpc('show interface', format='text')
<get-interface-information>
</get-interface-information>
>>>
```

これらの確認により、show interfaceは、\<get-route-information></get-route-information>というタグだとわかる。
次に、タグからRPCに変換する必要があるが、ハイフン( - )をアンダースコア( _ )に変え、山括弧を排除する。
すなわち、\<get-interface-information>の場合、RPCは、get_interface_information() になる。
あとはこのRPCメソッドを使えばいい。
尚、オプションを指定しない場合、XMLで返ってくるため、[lxml.etreeライブラリ](http://www.lifewithpython.com/2013/09/lxml-etree.html)もインポートし、整形して表示するためにetree.tostring()を使う。

・show interfaceを確認するサンプル

```
from jnpr.junos import Device
from lxml import etree

  dev = Device(xxxx,xxx,xxx,xx)
  dev.open()

int=dev.rpc.get_interface_information()
print(etree.tostring(int))
```

・showコマンドオプション利用(値なし)
尚、showコマンドのオプションで、値を使用しないものの場合、RPCメソッドのパラメータで=Trueとすれば確認できる。

例えば、show interface terseを確認するサンプル

```
dev.open()
int=dev.rpc.get_interface_information(terse=True)
print(etree.tostring(int))
```


・showコマンドオプション利用(値あり)
showコマンドのオプションで値を利用する場合は、オプションのXMLを同じようにRPCメソッドに変換し、イコールでオプション指定

例えばshow interfaceのinterfaceを指定する場合のタグは、\<interface-name> だとわかる。

```
> show interfaces ge-0/0/0 | display xml rpc
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1X49/junos">
    <rpc>
        <get-interface-information>
                <interface-name>ge-0/0/0</interface-name>
        </get-interface-information>
    </rpc>
    <cli>
```

よってRPCとしては、interface_nameとなるので、以下のように指定する。

```
>>> int=dev.rpc.get_interface_information(interface_name='ge-0/0/0')
>>> print(etree.tostring(int))
```

また、dev.rpc.rpc_method(normalize=True)とすると、返信されたXMLをノーマライズすることもできる。また、返信をXMLでない方法で表示させるのもできそう。




#4.まとめ
だらだらとメモのように書きましたが、
とりあえず、PyEzを使っていくつかの方法で情報取得を試してみました。
次回は設定変更をしてみようと思います。


#5.参考リンク
　 [PyEz サンプルスクリプト集(on Git by Nitin Kumar)](https://github.com/vnitinv/pyez-examples)