PyEZとJSNAPyを使ってみた。第四部: PyEZとJSNAPyでISP設定作業を自動化する編

PyEZとJSNAPyを使ってみた。の最終回です。今回はPyEZとJSNAPyを使って、ISPバックボーン作業でよくあるeBGP Peering設定作業を自動化した内容を紹介してきます。

[PyEZとJSNAPyを使ってみた。第一部: 概要編](http://qiita.com/taijijiji/items/065eef08f7b673cb7bb6)
[PyEZとJSNAPyを使ってみた。第二部: PyEZ使ってみた編](http://qiita.com/taijijiji/items/626cef18757d638251cf) 
[PyEZとJSNAPyを使ってみた。第三部: JSNAPy使ってみた編](http://qiita.com/taijijiji/items/b6e3da3d3aeb351ff7ff)
[PyEZとJSNAPyを使ってみた。第四部: PyEZとJSNAPyでISP設定作業を自動化する編] (http://qiita.com/taijijiji/items/983189f9bdebaa53e499)(イマココ)


# 最終回でやること
第一〜三部で学んだことを活かして、ISPバックボーンで頻繁に発生する作業のひとつである、BGP Peering作業を自動化してみます。

BGP Peeringは、AS番号を所有する組織のルータ同士がつながるためのeBGP接続する作業です。特定のデータセンター内でお互いのルータ同士を直接繋いだ状態で、eBGPの設定を投入することで、経路情報の交換およびトラフィック交換を実施します。

BGP Peering作業の一連の流れは以下の通りです。

1. 組織間での交渉/構内配線の手配
2. ケーブル配線
3. インタフェースの設定
4. 疎通確認
5. eBGP設定の投入
6. 経路広報の確認
7. トラフィック変移状態の確認

今回は論理設定作業である 3.〜 6. の工程を対象に自動化します。
そしていきなり全行程を全自動化するのではなく、commit直前までの設定/確認作業は自動化し、commitの実施可否は作業者の判断に委ねることによる半自動化を前提として進めました。

# 自動化システム構成
システム構成イメージです。

![system.png](https://qiita-image-store.s3.amazonaws.com/0/45596/ae48b25d-1848-544f-94ee-51ec68d40a69.png)


ここでは、設定が完了していないJUNOSルータ「Firefly1」に対して、PyEZライブラリおよびJSNAPyライブラリを介してインタフェース設定およびeBGP設定を投入していくことをストーリーとしています。

従来から作業者が作成している作業手順書およびルータコンフィグの代替として、本システムでは作業者は以下のような「シナリオファイル」を作成します。このシナリオファイルをシナリオ実行プログラムに読み込ませることで、作業者が意図した手順通りにルータ設定およびネットワーク正常性確認の工程を進めていきます。本システムでは、作業者は従来の手順書やルータコンフィグを事前作成することなく、このシナリオファイルを作成するだけで作業できるので、作業者および査閲者の負荷を軽減させることを狙いとしています。

```yaml:シナリオファイル
purpus:  |
  本作業は、株式会社ABC(AS65002)が運用するルータと、
  拠点Aでプライベートピアを構築することを目的としている。
  経路交換は1経路ずつ受信/送信を行う予定であり、作業による
  ネットワークの影響は軽微であることを想定している。
operator: Taiji Tsuchiya
operation_date: 20161115
hosts:
  management_ipaddress: 192.168.34.16
  hostname: firefly1
  model: firefly-perimeter
  username: user1
  password: password1
scenario:
  - test_hostname
  - test_model
  - test_interface:
      interface_name: ge-0/0/2
      interface_status: up
  - set_add_interface:
      interface_name: ge-0/0/2
      interface_address_ipv4: 192.168.35.1
      interface_subnet_ipv4: 30
      interface_description: AS65002_peer
  - test_interface:
      interface_name: ge-0/0/2
      interface_status: up
  - set_add_bgp_neighbor:
      interface_name: ge-0/0/2
      neighbor_asnum: 65002
      neighbor_address_ipv4: 192.168.35.2
      neighbor_description: AS65002_peer
  - test_bgp_neighbor:
      neighbor_address_ipv4: 192.168.35.2
      neighbor_status: Established
  - set_add_bgp_policy_external:
      external_policy_name: AS65002_export
      advertised_route_address_ipv4: 10.10.10.0
      advertised_route_subnet_ipv4: 24
      interface_name: ge-0/0/2
      neighbor_address_ipv4: 192.168.35.2
  - sleep_10sec
  - test_bgp_received_route:
      neighbor_address_ipv4: 192.168.35.2
      received_route_address_ipv4: 10.10.30.0
      received_route_subnet_ipv4: 24
  - test_bgp_advertised_route:
      neighbor_address_ipv4: 192.168.35.2
      advertised_route_address_ipv4: 10.10.10.0
      advertised_route_subnet_ipv4: 24
```

上記のシナリオファイルをみると、初見では英単語だらけで読みにくいと思われるかもしれません。シナリオファイルではルータ作業時に必要となる「手順名」とそれに必要となる「パラメータ」の組み合わせによって構成されています。。「set_...」で始まる手順がルータ設定作業、「test_...」から始まる手順がルータ確認作業を示しています。

普段から作業手順書やルータコンフィグを作られている方や査閲されている方からすると、しっかりシナリオファイルを読み込めば、どういった手順を実現しようとしているのか想像していただけるのではないでしょうか。そして「ルータコンフィグを準備するよりはよっぽどラク」といった感想を持っていただけるのではないでしょうか。

本システムの設計思想としては、「ありきたりな日本語だらけの作業手順書よりも、シナリオファイルのように極限まで情報を簡略化したほうが、作成者/査閲者が本来チェックすべきポイントに対して(無駄な確認項目が無い分)神経を集中させて査閲に臨むことができるのではないだろうか」というアイディアをもって、このようなシステムを実装しています。


ここで、「本システムでは作業者はルータコンフィグは作らない」という話をしましたが、「じゃあどうやって投入コンフィグ作るの？」と疑問に思われたかもしれません。
本システムでは、ルータコンフィグは以下のようなテンプレートファイルを事前にシステム内部にて複数パターン分を保持しておき、呼び出される手順ごとに対応したテンプレートファイルを参照して、ルータコンフィグを自動生成することを実装しています。

```:テンプレートファイル_BGPネイバー設定の場合
protocols {
    bgp {
        family inet {
            unicast;
        }
        group {{ interface_name }} {
            type external;
            neighbor {{ neighbor_address_ipv4 }} {
                description {{ neighbor_description }};
                peer-as {{ neighbor_asnum }};
            }
        }
    }
}
```

上記のようなテンプレートファイル(Jinja2形式)に対して、シナリオファイルから抽出したパラメータ(YAML形式)をマッチングさせることで、ルータコンフィグファイルを自動生成しています。各手順ごとに、パラメータをシナリオファイルから抽出してルータコンフィグを生成することで、作業者は従来のルータコンフィグ事前作成作業の手間を省くことができます。

```yaml:テンプレート用パラメータ(シナリオファイルより抽出)
- set_add_bgp_neighbor:
      interface_name: ge-0/0/2
      neighbor_asnum: 65002
      neighbor_address_ipv4: 192.168.35.2
      neighbor_description: AS65002_peer
```

```:自動生成されたルータコンフィグファイル
protocols {
    bgp {
        family inet {
            unicast;
        }
        group ge-0/0/2 {
            type external;
            neighbor 192.168.35.2 {
                description AS65002_peer;
                peer-as 65002;
            }
        }
    }
}
```

上記のような流れで、ルータ設定手順およびルータ確認手順をシナリオファイルから抽出・生成したものを順番通りに実行していくことで、作業者が意図した順番で作業を進めていくことができます。

# プログラム実行結果
最終的に作った自動化プログラムはGitHubで公開しています。
https://github.com/taijiji/scenarioJUNOS

firefly1(インターフェース設定未実施、eBGP設定未実施)、firely2(インタフェース設定完了、eBGP設定完了)を準備した状態で、プログラムを実行すると以下のように動作します。左画面が自動化システム、右上がfirefly1ルータ,右下がfirefly2ルータを示しています。

![demo_v4.gif](https://qiita-image-store.s3.amazonaws.com/0/45596/c29b2bca-e4e0-aab9-58c7-f2e382ceea2f.gif)

緑文字は「正常性を確認している部分」、赤文字は「異常を確認している部分」、黃文字は「作業者に判断を委ねたい部分」を示しています。

プログラムの実行結果は下記のように表示されています。

![Screen Shot 2016-12-02 at 8.21.18 AM.png](https://qiita-image-store.s3.amazonaws.com/0/45596/bb6b4404-ea84-128a-c6d5-4575ce44a2a1.png)
![Screen Shot 2016-12-02 at 8.21.35 AM.png](https://qiita-image-store.s3.amazonaws.com/0/45596/a19f75c3-b707-50d0-7ea7-a1cdb682d98f.png)
![Screen Shot 2016-12-02 at 8.22.03 AM.png](https://qiita-image-store.s3.amazonaws.com/0/45596/0429eebd-9d78-8544-e7b6-f860eb9f43ed.png)
↓ここはデモ用にあえてNGを出しています。BGPセッション確立には数十秒時間がかかるので、本来はSleepして待ってあげないと、Establishedにはなりません。
![Screen Shot 2016-12-02 at 8.22.25 AM.png](https://qiita-image-store.s3.amazonaws.com/0/45596/80e71156-02d4-e807-0a9c-fe9bf3781747.png)
![Screen Shot 2016-12-02 at 8.22.37 AM.png](https://qiita-image-store.s3.amazonaws.com/0/45596/7a852322-a2ef-5d22-85dc-fbbc107a31a0.png)


たくさん文字が表示されて煩わしいかもしれませんが、実際の作業中は、異常が発生する可能性のある「黄文字」と「赤文字」だけを集中しておけばよく、緑文字は集中して確認する必要はありません。これにより作業者の負担はぐっと減ることになります。そして作業者は、本来最も集中しなければならない危険な異常の察知に、全神経を集中した状態で作業に臨むことができます。

# まとめ
今回は、従来の作業手順書を簡素化したシナリオファイルをベースにした自動化システムを構築することができました。PyEZとJSNAPyを使ったことで、大きな壁にハマることなく、実働二週間程度でこのシステムを構築することができました。（そのうち半分くらいが、ドキュメントを読み込む時間でした。）

PyEZは、非常に協力なライブラリであり、ドキュメントも整備されるので詰まるところがほとんどありませんでした。(あえてあげるなら、私がNETCONF over SSHの利用ポートがTCP830であることを知らずに、トラブったくらいです。)

JSNAPyは、テストツールを作成するために、とても役立ちました。本システムを正規表現ゼロで実装することができたことは、手早く実装するために何よりの助けになりました。
ただしツール自体が新しいこともあり、ドキュメントはまだ整備されていない部分もあり、数回ハマりました。とくにxpathの指定やテスト結果を取得するための手段がわかりづらく、「こういうテスト結果とりたいのだけど、テストファイルをどう記述すれば実現できるのだろう」と感じることが多々有りました。実際はしかたがないので思いつく限りのテストの条件を書きまくって実行し、結果をみながら上手くいったものを採用する、という人海戦術的に解決してしまうことが多かったです。
今後もう少しテストファイルのサンプルが増えてくると、このあたりでハマることは減ってくるのかと想像しています。
時間が足らずにテストファイル作成を実現できなかったことはいくつかあります。例えば、test_pingやtest_tracerouteが失敗したときの結果を取得する方法、
「目的の経路以外が受信/送信していないことを確認する条件文(二重否定)」「BGPが動いていないことを確認する方法」など、少し複雑な確認項目は未実装に終わってしまいました。

最後に今回作ったデモプログラムについてですが、時間不足のために実装不十分ではあったものの、デモを通して次世代の理想的なネットワーク作業の形を、具体的なイメージをもって伝えることができたことはよかったです。

本システムを導入するための課題としては「運用者、査閲者がこのYAML形式のシナリオファイルを受け入れてくれるか」「マルチベンダー対応ツールとして、他社ルータにも同じ仕組みを展開してくことができるか」といったいくつかの課題が残っています。そのあたりは実際にシステムを導入しながら、運用現場のニーズにあわせてシステムを徐々にブラッシュアップしていければいいかなと考えています。