pyATS|Genieの隠れ必殺技Blitzを用いて高速自動化テスト作成

この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2019 の 11 日目として投稿しています。
2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco

# はじめに

こんにちは。[pyATS|Genie](https://developer.cisco.com/pyats/) 開発チームに所属する @tahigash3 です。今回は [pyATS|Genie](https://developer.cisco.com/pyats/) を使ったネットワークテスト作成の簡単な方法を紹介します。

過去の記事で簡単に [pyATS|Genie](https://developer.cisco.com/pyats/) の紹介とインストールについては触れているので、こちらも合わせて参照ください。
[pyATS/GenieとRobot Framework で簡単にマルチベンダーネットワークをチェックする](https://qiita.com/tahigash/items/ceb0809a4a9464c521b3)

# ネットワーク自動化の悩み

まだネットワークの自動化をやったことがない人の悩みを列挙してみました。

1. いつも python の知識が要求される
2. 自動化ツールのベンダ毎のモジュールを覚えないといけない
3. せっかく覚えた CLI ベースの知識を生かしたい
4. 古い機器や構成もせっかくなら自動化したい

今回はそういう悩みを少しでも解消すべく [pyATS|Genie](https://developer.cisco.com/pyats/) の隠し技 Blitz を紹介します。
**ネットワークエンジニアの為の簡単にネットワーク自動化できる方法です。**

# pyATS|Genie のインストール

上記の[過去記事](https://qiita.com/tahigash/items/ceb0809a4a9464c521b3)ににも書いていますが、一応インストール方法です。下記は MacOS で pyenv/virtualenv を使った場合の例。

```bash

$ pyenv install 3.7.3
$ pyenv virtualenv 3.7.3 genie_env
$ pyenv activate genie_env
(genie_env)$ python -V
Python 3.7.3
(genie_env)$ pip install genie
```

以降はこの python virtualenv 環境にいる前提で書いています。

# ネットワーク構成

今回は前回に似た下記の構成を使います。機器は [VIRL](http://virl.cisco.com/) に起動したものを使っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/b68d69b9-e71c-e9e3-a6f8-35b3cbed1f9e.png)

| Hostname     | Os    | Version   |
|:-------------|:------|:----------|
| iosv-1       | IOS   | 15.7(3)M3 |
| iosv-2       | IOS   | 15.7(3)M3 |
| iosv-3       | IOS   | 15.7(3)M3 |
| csr1000v-1   | IOSXE | 16.9.1    |
| iosxr9000-1  | IOSXR | 6.5.1     |
| nx-osv9000-1 | NXOS  | 9.2.1     |

# 何を自動化するか？

今回は紹介する Blitz を理解してもらうためにも、比較的簡単なものを紹介したいと思います。

1. snmp コミュニティの設定追加
2. iBGP ネイバーの確立(iosv-1/iosv-2 が RR で、iosv-3/csr1000v-1/iosxr9000-1,nx-osv9000-1がRR client)

# pyATS|Genie Blitz で必要なのは2ファイルのみ!!!

今回作成するファイルは下記の2つになります。

## ネットワーク構成ファイル (testbed.yaml 今回は略してtb.yaml)

ネットワーク構成ファイルは皆んな大好き YAML で記載します。ネットワーク機器の情報を決まったフォーマットで記載しますが、項目を見ればネットワークエンジニアであれば問題なく作成できるかと思います。

トポロジーに見える iosvl2-1 及び ioslv2-2 は今回の作業対象にはしないので、下記の tb.yaml には含まれていません。

全ての機器は jump_host 経由で SSH 接続する形のネットワーク構成ファイルになっています。
さりげなく入れておりますが、**`ssh_options` で ssh コマンドのオプションを指定することができます**。

```yaml:tb.yaml
devices:
  csr1000v-1:
    alias: uut
    connections:
      ssh:
        ip: 172.16.1.234
        protocol: ssh
        proxy: jump_host
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: iosxe
    platform: iosxe
    type: CSR1000v
  iosv-1:
    alias: iosv-1
    connections:
      ssh:
        ip: 172.16.1.235
        protocol: ssh
        proxy: jump_host
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: ios
    platform: ios
    type: IOSv
  iosv-2:
    alias: iosv-2
    connections:
      ssh:
        ip: 172.16.1.236
        protocol: ssh
        proxy: jump_host
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: ios
    platform: ios
    type: IOSv
  iosv-3:
    alias: iosv-3
    connections:
      ssh:
        ip: 172.16.1.237
        protocol: ssh
        proxy: jump_host
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: ios
    platform: ios
    type: IOSv
  iosxrv9000-1:
    alias: iosxrv9000-1
    connections:
      ssh:
        ip: 172.16.1.240
        protocol: ssh
        proxy: jump_host
        ssh_options: -o HostKeyAlgorithms=+ssh-dss
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: iosxr
    platform: iosxrv9k
    type: IOS XRv 9000
  nx-osv9000-1:
    alias: nx-osv9000-1
    connections:
      ssh:
        ip: 172.16.1.51
        protocol: ssh
        proxy: jump_host
    credentials:
      default:
        password: Cisc0123
        username: admin
      enable:
        password: Cisc0123
    os: nxos
    platform: n9kv
    type: NX-OSv 9000
  jump_host:
    connections:
      cli:
        ip: 172.25.192.134
        port: 22
        protocol: ssh
    credentials:
      default:
        password: VIRL
        username: virl
    os: linux
    type: linux
```

## 自動化したい項目を書くトリガーデータファイル(trigger_datafile.yaml)

自動化したいテスト内容は `trigger datafile` に記載します。ファイル名は何でも構わないのですが、trigger datafile というのが分かるように今回は `trigger_datafile.yaml` とします。

それでは snmp コミュニティを設定して設定確認、設定削除、設定削除確認の trigger_datafile.yaml です。

```yaml:trigger_datafile.yaml
TriggerBlitzConfigureSnmpCommunity:
  groups: ['blitz', 'snmp']
  source:
    pkg: genie.libs.sdk
    class: triggers.blitz.blitz.Blitz
  devices: ['csr1000v-1']
  configure:
    devices:
      csr1000v-1: |
        snmp-server community blitz
    sleep: 10
  validate_configure:
    devices:
      csr1000v-1:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
  unconfigure:
    devices:
      csr1000v-1: |
        no snmp-server community blitz
  validate_unconfigure:
    devices:
      csr1000v-1:
        1:
          command: show running-config
          exclude:
           - 'snmp-server community blitz'
```

上記はコピペ用として、下記に各項目に説明を入れました。

```yaml:trigger_datafile.yaml
TriggerBlitzConfigureSnmpCommunity:       # テスト項目名。特に何で良い
  groups: ['blitz', 'snmp']               # グループを指定。リストで書ける。genie run コマンドで使う
  source:                                 # Blitz を使う旨、Blitzコードの場所を指定。おまじないとして覚える
    pkg: genie.libs.sdk                   
    class: triggers.blitz.blitz.Blitz     
  devices: ['csr1000v-1']                 # デバイスを指定。複数台指定すると台数分同じ内容が繰り返される点に注意
  configure:                              # 設定追加のセクション
    devices:
      csr1000v-1: |                       # デバイスホスト名
        snmp-server community blitz       # 指定したデバイスに合った設定を書く。複数行でもOK
    sleep: 10                             # 設定後に待ち時間（秒）を追加
  validate_configure:                     # 設定追加の確認セクション
    devices:
      csr1000v-1:                         # デバイスホスト名
        1:                                # 確認1。同じ要領で複数2,3として書くことが可能
          command: show running-config    # show コマンド
          include:                        # include は show コマンドに下記アウトプットが含まれるのを確認
           - 'snmp-server community blitz'
  unconfigure:                            # 設定削除のセクション
    devices:
      csr1000v-1: |                       # デバイスホスト名
        no snmp-server community blitz    # 指定したデバイスに合った設定を書く。複数行でもOK
  validate_unconfigure:                   # 設定削除の確認セクション
    devices:
      csr1000v-1:                         # デバイスホスト名
        1:                                # 確認1。同じ要領で複数2,3として書くことが可能
          command: show running-config    # show コマンド
          exclude:                        # exclude は show コマンドに下記アウトプットが含まれないのを確認
           - 'snmp-server community blitz'
```

Blitz の自動化項目として指定できるのはシンプルで下記4つになります。

1. configure : 設定追加
2. validate_configure : 設定追加の確認
3. unconfigure : 設定削除
4. validate_unconfigure : 設定削除の確認

**また上記の全てが必ず存在する必要はなく、必要なものだけ書くことができます。**

# genie run で実行してみる

それでは前述の trigger_datafile.yaml を genie run コマンドを実行します。
genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "And('blitz')"

```bash
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "And('blitz')"
(snip)
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: |                                Easypy Report                                 |
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: pyATS Instance   : /Users/tahigash/.pyenv/versions/3.7.3/envs/genie_env
2019-12-09T21:20:50: %EASYPY-INFO: Python Version   : cpython-3.7.3 (64bit)
2019-12-09T21:20:50: %EASYPY-INFO: CLI Arguments    : /Users/tahigash/.pyenv/versions/genie_env/bin/genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups And('blitz')
2019-12-09T21:20:50: %EASYPY-INFO: User             : tahigash
2019-12-09T21:20:50: %EASYPY-INFO: Host Server      : TAHIGASH-M-K2AT
2019-12-09T21:20:50: %EASYPY-INFO: Host OS Version  : Mac OSX 10.14.6 (x86_64)
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: Job Information
2019-12-09T21:20:50: %EASYPY-INFO:     Name         : job
2019-12-09T21:20:50: %EASYPY-INFO:     Start time   : 2019-12-09 21:19:45.983371
2019-12-09T21:20:50: %EASYPY-INFO:     Stop time    : 2019-12-09 21:20:49.931930
2019-12-09T21:20:50: %EASYPY-INFO:     Elapsed time : 0:01:03.948559
2019-12-09T21:20:50: %EASYPY-INFO:     Archive      : /Users/tahigash/.pyats/archive/19-Dec/job.2019Dec09_21:19:44.951298.zip
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: Total Tasks    : 1
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: Overall Stats
2019-12-09T21:20:50: %EASYPY-INFO:     Passed     : 2
2019-12-09T21:20:50: %EASYPY-INFO:     Passx      : 1
2019-12-09T21:20:50: %EASYPY-INFO:     Failed     : 0
2019-12-09T21:20:50: %EASYPY-INFO:     Aborted    : 0
2019-12-09T21:20:50: %EASYPY-INFO:     Blocked    : 0
2019-12-09T21:20:50: %EASYPY-INFO:     Skipped    : 0
2019-12-09T21:20:50: %EASYPY-INFO:     Errored    : 0
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO:     TOTAL      : 3
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: Success Rate   : 100.00 %
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: |                             Task Result Summary                              |
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: Task-1: genie_testscript.common_setup                                      PASSX
2019-12-09T21:20:50: %EASYPY-INFO: Task-1: genie_testscript.TriggerBlitzConfigureSnmpCommunity.csr1000v-1    PASSED
2019-12-09T21:20:50: %EASYPY-INFO: Task-1: genie_testscript.common_cleanup                                   PASSED
2019-12-09T21:20:50: %EASYPY-INFO:
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: |                             Task Result Details                              |
2019-12-09T21:20:50: %EASYPY-INFO: +------------------------------------------------------------------------------+
2019-12-09T21:20:50: %EASYPY-INFO: Task-1: genie_testscript
2019-12-09T21:20:50: %EASYPY-INFO: |-- common_setup                                                           PASSX
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- connect                                                           PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- configure                                                        SKIPPED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- configuration_snapshot                                            PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- save_bootvar                                                       PASSX
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- learn_system_defaults                                             PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   `-- initialize_traffic                                               SKIPPED
2019-12-09T21:20:50: %EASYPY-INFO: |-- TriggerBlitzConfigureSnmpCommunity.csr1000v-1                         PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- apply_configuration                                               PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- validate_configuration                                            PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |   |-- STEP 1: Verify the output of 'show running-config'            PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |   `-- STEP 1.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   |-- remove_configuration                                              PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |   `-- validate_unconfiguration                                          PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |       |-- STEP 1: Verify the output of 'show running-config'            PASSED
2019-12-09T21:20:50: %EASYPY-INFO: |       `-- STEP 1.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T21:20:50: %EASYPY-INFO: `-- common_cleanup                                                        PASSED
2019-12-09T21:20:50: %EASYPY-INFO:     |-- verify_configuration_snapshot                                     PASSED
2019-12-09T21:20:50: %EASYPY-INFO:     `-- stop_traffic                                                     SKIPPED
2019-12-09T21:20:50: %EASYPY-INFO: Sending report email...
2019-12-09T21:20:50: %EASYPY-INFO: Missing SMTP server configuration, or failed to reach/authenticate/send mail. Result notification email failed to send.
2019-12-09T21:20:50: %EASYPY-INFO: Done!

Pro Tip
-------
   Use the following command to view your logs locally:
       pyats logs view
```

genie run コマンドを実行すると一連のログがターミナル画面上に表示され、上記のように CLI 上で結果のサマリーを最後に見ることできます。

# GUI で綺麗にログを見よう

前述の CLI 上の結果の後に Pro Tip として表示されていますが、`pyats logs view` と入力することで、一番最新のログを Webブラウザ で開くことができます。

```
(genie_env)$ pyats logs view
```
まず開くと見えるのは `Overview` 画面です。何個の項目が実行されたか、実行結果のサマリー(Passed/Failed)が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/3b1cc5c2-449a-4448-89bb-6261043a9283.png)

上のタブから `Task-1` をクリックするとテストされた項目がリスト表示され、こちらでも各項目毎に PASSED/FAILED といった結果を見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/5e14e58a-ce3b-61c1-b0e5-4ab2d9fe30dc.png)

`commonSetup`や`commonCleanup`は`genie run`を実行した際にデフォルトで実行される項目となりますが、機器への接続やコンフィグの確認などの基本的な情報取得、確認がメインとなりますが、今回は詳細は割愛します。

各項目をクリックすると、実行されたログが確認できます。試しに`TriggerBlitzConfigureSnmpCommunicy`の`apply_configuration`を開いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/d2f9b7e9-90a1-a223-f2fd-ee8c5eebaf68.png)
すると上記のように`trigger_datafile.yaml`で指定した設定内容が設定されているのが確認できます。

次は`validate_configuration`をクリックしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/f2c4c37e-490b-68b3-4bd2-c16ae57c4dc8.png)
こちらも`trigger_datafile.yaml`に記載した通り、`show run`を実行して`snmp-server community`のラインが含まれることがチェックされています。

割愛しますが、`remote_configuration`及び`validate_unconfiguration`も同じ要領です。
**これは`Logviewer`という機能ですが簡単にログが確認でき非常に便利です。Webブラウザでログを見るためにGUIツールをインストールしたりする必要はありません。**

*NOTE: pyATS|Genie チームではこれとは別に多機能な GUI ツールも開発しており、外部へリリースする予定ですのでご期待ください。Cisco Live US 2019 などイベントでは既にデモを含め紹介したりしています。*

# SNMPコミュニティを全機器へ設定する

少し話が GUI にズレてしまいました。話をネットワーク自動化に戻します。先ほど設定追加、削除した例を元に全機器を設定変更してみます。
各項目の詳細は前述したので、全機器を設定する trigger_datafile.yaml をサクッと載せます。

```yaml:trigger_datafile.yaml
TriggerBlitzConfigureSnmpCommunity:
  groups: ['blitz', 'snmp']
  source:
    pkg: genie.libs.sdk
    class: triggers.blitz.blitz.Blitz
  devices: ['csr1000v-1']
  configure:
    devices:
      csr1000v-1: |
        snmp-server community blitz
      iosv-1: |
        snmp-server community blitz
      iosv-2: |
        snmp-server community blitz
      iosv-3: |
        snmp-server community blitz
      iosxrv9000-1:
        snmp-server community blitz
      nx-osv9000-1:
        snmp-server community blitz
  validate_configure:
    devices:
      csr1000v-1:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
      iosv-1:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
      iosv-2:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
      iosv-3:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
      iosxrv9000-1:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
      nx-osv9000-1:
        1:
          command: show running-config
          include:
           - 'snmp-server community blitz'
```
ポイントしては下記になります。

1. devices には **1台のみ** 指定する
2. 設定追加のみ行いたいので、`unconfigure`/`validate_unconfigure`は削除
3. 各ルータに合う設定内容と確認コマンド、`include`を指定

ここまで書いて気づいたのですが、せっかく IOSXE, IOSXR, NXOS 混在の環境なのに全て同じ設定、確認方法になってしまった。。。後述の iBGP の設定では内容が異なるのでご安心ください。

同じ`genie run`コマンドを実行してみます。結果のサマリーが少し見え方が変わりましたね。

```
(genie_dev)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "And('blitz')"
(snip)
2019-12-09T22:02:29: %EASYPY-INFO: |-- TriggerBlitzConfigureSnmpCommunity.csr1000v-1                         PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |-- apply_configuration                                               PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |-- validate_configuration                                            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 1: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 1.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 2: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 2.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 3: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 3.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 4: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 4.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 5: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 5.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   |-- STEP 6: Verify the output of 'show running-config'            PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |   `-- STEP 6.1: Verify that 'snmp-server community blitz' is ...    PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   |-- remove_configuration                                              PASSED
2019-12-09T22:02:29: %EASYPY-INFO: |   `-- validate_unconfiguration                                          PASSED
(snip)
```
`Logviewer`(pyats logs viewコマンド)で`apply_configuration`を確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/c09f6c1e-05f6-46cb-da63-a98d14b04d07.png)
上記を見ると各機器毎に合わせてちゃんと設定されているのが確認できます。`IOSXR`ではちゃんと`commit`がされているのが分かります。

`validate_configuration`を見てみると、確認毎に`STEP`が分かれて実行されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/a0b1beae-6e36-a28a-c9c3-b73ec5178664.png)

STEPは`trigger_datafile.yaml`に記載した順番になる為、`iosxrv9000-1`のもの(最後から2つ目 STEP5 )を開くと、ちゃんと`IOSXR`でログ確認されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/8fcca15b-fb8f-edd2-1f7e-f0cbbd899691.png)

また、`remove_configuration`/`validate_unconfiguration`も表示はされますが、`trigger_datafile.yaml`から削除しているため、下記のように何も実行はされません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/863ccd5b-d68f-ef0f-f8de-803b621627ea.png)

ここまでどうでしょうか？プログラミング不要で、かつ知っている`CLI`コマンドで設定投入、確認を自動化できました。

少し長くなってきていますが、次は応用編です。

# iBGP を全機器で設定する

冒頭で書いた通り、ネットワーク構成の `iosv-1`/`iosv-2`を RR として、iBGP を設定します。

iBGP設定の為の各ルータのループバックアドレスは下記の通りです。BGP AS は 65000 とします。

| Hostname     | Interface | Address        |
|:-------------|:----------|:---------------|
| iosv-1       | Loopback0 | 10.11.11.11/32 |
| iosv-2       | Loopback0 | 10.22.22.22/32 |
| iosv-3       | Loopback0 | 10.33.33.33/32 |
| csr1000v-1   | Loopback0 | 10.44.44.44/32 |
| iosxr9000-1  | Loopback0 | 10.55.55.55/32 |
| nx-osv9000-1 | Loopback0 | 10.66.66.66/32 |

`trigger_datafile.yaml`の説明は上でしましたので、いきなり内容を載せます。IBGP設定ということで、新しいアイテムとして`TriggerBlitzConfigureIBGP`と名付けました。

```yaml:trigger_datafile.yaml
TriggerBlitzConfigureIBGP:
  groups: ['blitz', 'bgp']
  source:
    pkg: genie.libs.sdk
    class: triggers.blitz.blitz.Blitz
  devices: ['csr1000v-1']
  configure:
    devices:
      iosv-1: |
        router bgp 65000
         neighbor IBGP peer-group
         neighbor IBGP remote-as 65000
         neighbor IBGP update-source lo0
         neighbor IBGP route-reflector-client
         neighbor 10.33.33.33 peer-group IBGP
         neighbor 10.44.44.44 peer-group IBGP
         neighbor 10.55.55.55 peer-group IBGP
         neighbor 10.66.66.66 peer-group IBGP
      iosv-2: |
        router bgp 65000
         neighbor IBGP peer-group
         neighbor IBGP remote-as 65000
         neighbor IBGP update-source lo0
         neighbor IBGP route-reflector-client
         neighbor 10.33.33.33 peer-group IBGP
         neighbor 10.44.44.44 peer-group IBGP
         neighbor 10.55.55.55 peer-group IBGP
         neighbor 10.66.66.66 peer-group IBGP
      iosv-3: |
        router bgp 65000
         neighbor RR peer-group
         neighbor RR remote-as 65000
         neighbor RR update-source lo0
         neighbor 10.11.11.11 peer-group RR
         neighbor 10.22.22.22 peer-group RR
      csr1000v-1: |
        router bgp 65000
         neighbor RR peer-group
         neighbor RR remote-as 65000
         neighbor RR update-source lo0
         neighbor 10.11.11.11 peer-group RR
         neighbor 10.22.22.22 peer-group RR
      iosxrv9000-1: |
        router bgp 65000
         address-family ipv4 unicast
         neighbor 10.11.11.11
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
         neighbor 10.22.22.22
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
      nx-osv9000-1: |
        feature bgp
        router bgp 65000
         address-family ipv4 unicast
         neighbor 10.11.11.11
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
         neighbor 10.22.22.22
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
    sleep: 60
  validate_configure:
    devices:
      iosv-1:
        1:
          command: show ip bgp neighbors 10.33.33.33
          include:
           - 'BGP state = Established'
        2:
          command: show ip bgp neighbors 10.44.44.44
          include:
           - 'BGP state = Established'
        3:
          command: show ip bgp neighbors 10.55.55.55
          include:
           - 'BGP state = Established'
        4:
          command: show ip bgp neighbors 10.66.66.66
          include:
           - 'BGP state = Established'
      iosv-2:
        1:
          command: show ip bgp neighbors 10.33.33.33
          include:
           - 'BGP state = Established'
        2:
          command: show ip bgp neighbors 10.44.44.44
          include:
           - 'BGP state = Established'
        3:
          command: show ip bgp neighbors 10.55.55.55
          include:
           - 'BGP state = Established'
        4:
          command: show ip bgp neighbors 10.66.66.66
          include:
           - 'BGP state = Established'
      iosv-3:
        1:
          command: show ip bgp neighbors 10.11.11.11
          include:
           - 'BGP state = Established'
        2:
          command: show ip bgp neighbors 10.22.22.22
          include:
           - 'BGP state = Established'
      csr1000v-1:
        1:
          command: show ip bgp neighbors 10.11.11.11
          include:
           - 'BGP state = Established'
           - 'max data segment is 1460 bytes'
        2:
          command: show ip bgp neighbors 10.22.22.22
          include:
           - 'BGP state = Established'
           - 'max data segment is 1500 bytes'
      iosxrv9000-1:
        1:
          command: show bgp instance all sessions
          parsed:
           - "[instance][default][vrf][default][neighbors][10.11.11.11][nbr_state][Established]"
           - "[instance][default][vrf][default][neighbors][10.22.22.22][nbr_state][Established]"
      nx-osv9000-1:
        1:
          command: show bgp vrf all all summary
          parsed:
           - "[vrf][default][neighbor][10.11.11.11][address_family][ipv4 unicast][state][(?!Idle)]"
           - "[vrf][default][neighbor][10.22.22.22][address_family][ipv4 unicast][state][(?!Idle)]"
           - "[vrf][default][neighbor][10.22.22.22][address_family][ipv4 unicast][as][65000]"
```

今回新しく試した点を見ていきます。

## configure で複数行の設定と待ち時間(sleep)の挿入

下記のように設定を複数行に渡って設定し、`configure`の最後に`sleep: 60`を入れて BGP Neighbor が Up するのを待つように60秒の待ち時間を挿入しています。

```yaml
(snip)
      nx-osv9000-1: |
        feature bgp
        router bgp 65000
         address-family ipv4 unicast
         neighbor 10.11.11.11
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
         neighbor 10.22.22.22
          remote-as 65000
          update-source lo0
          address-family ipv4 unicast
    sleep: 60
(snip)
```
`Logviewer`で`apply_configuration`を見ると下記のように機器のコンソールと同じように設定されているのが確認でき、60秒間スリープしているのも見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/9c21f874-ca45-655a-7564-2cdfc897f945.png)

## BGP Neighbor Up を複数の方法で確認

先の SNMPコミュニティ の例では `show run` からの確認のみでしたが、今回は `show` コマンドを使って3パターンで確認しました。

### 1. include の組み合わせ
下記のように1デバイスに対して、複数のコマンドで`include`で確認。

```yaml
      iosv-1:
        1:
          command: show ip bgp neighbors 10.33.33.33
          include:
           - 'BGP state = Established'
        2:
          command: show ip bgp neighbors 10.44.44.44
          include:
           - 'BGP state = Established'
        3:
          command: show ip bgp neighbors 10.55.55.55
          include:
           - 'BGP state = Established'
        4:
          command: show ip bgp neighbors 10.66.66.66
          include:
           - 'BGP state = Established'
```
下記のように`inxclude`に複数のキーワードを設定して確認。

```yaml
      csr1000v-1:
        1:
          command: show ip bgp neighbors 10.11.11.11
          include:
           - 'BGP state = Established'
           - 'max data segment is 1460 bytes'
        2:
          command: show ip bgp neighbors 10.22.22.22
          include:
           - 'BGP state = Established'
           - 'max data segment is 1500 bytes'
```
ちなみに `MSS(max data segement)` の確認では項番2は実際にはデフォルトの 1460 bytes となるので `FAILED` になります。項目STEP12としては`FAILED`になりますが、ちゃんとSTEP12.1の`Established`は確認できているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/f4f6de84-9861-06ea-d072-a5f2cc94db58.png)

### 2. parsed を使う

次の例は`parsed`を今回初めて使いました。

```yaml
      iosxrv9000-1:
        1:
          command: show bgp instance all sessions
          parsed:
           - "[instance][default][vrf][default][neighbors][10.11.11.11][nbr_state][Established]"
           - "[instance][default][vrf][default][neighbors][10.22.22.22][nbr_state][Established]"
```
これは `include` は showコマンド の出力から指定した文字列が該当出力に含まれるかどうかを確認していますが、`parsed` では Genei Parser の Schema に合わせてチェックします。

IOSXR の`show bgp instance all sessions`の Schema は下記の通りです。

https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/parsers/show%20bgp%20instance%20all%20sessions

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/416265f3-f306-077c-f0c6-9a96a0924645.png)

`Logviewer` 上のログでは下記のように確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/381f2b40-f8f4-88a9-890c-a5cc142e784e.png)

### 3. parsed で否定チェックと複数のキーをチェック

下記は同じく`parsed`を使っていますが、**(?!) によって、否定表現で指定したものに該当しないものとしてチェック**しています。その為、`state`が`Idle`でなければ`PASSED`になるという形です。
`Parsed`なので、先の例と同じく指定する階層は Genie Parser の Schema に一致したものを記載します。

```yaml
      nx-osv9000-1:
        1:
          command: show bgp vrf all all summary
          parsed:
           - "[vrf][default][neighbor][10.11.11.11][address_family][ipv4 unicast][state][(?!Idle)]"
           - "[vrf][default][neighbor][10.22.22.22][address_family][ipv4 unicast][state][(?!Idle)]"
           - "[vrf][default][neighbor][10.22.22.22][address_family][ipv4 unicast][as][65000]"
```
また、条件を追加して `10.22.22.22` のネイバーについては AS番号 が 65000 であることも合わせて確認しています。

`Logviewer`で見るとこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/649ae1a4-1c16-bcdd-9099-45b793603bf6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309712/7fe16bb6-6028-a27a-d622-3a5afa0e0421.png)

## genie run の実行方法

最後に genie run の使い方を簡単にご紹介したいと思います。

```yaml:trigger_datafile.yaml
TriggerBlitzConfigureSnmpCommunity:
  groups: ['blitz', 'snmp']
(snip)

TriggerBlitzConfigureIBGP:
  groups: ['blitz', 'bgp']
(snip)
```

今回は上記のように2つのテストケースを作成し、`groups`を設定しています。`groups`は名前の通り、グルーピングになっていますので、`groups`で実行対象を選択できるようになります。

### TriggerBlitzConfigureSnmpCommunity と TriggerBlitzConfigureIBGP の両方を実行したい

下記のように両方に含まれてる`blitz`を And に指定します。(1つのみ指定する場合は Orでも可)

```bash
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "And('blitz')"
または
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "Or('blitz')"
```

既にご察しいただいているかもしれませんが、And/Or で書けるため、下記でも両方を実行できます。

```bash
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "Or('snmp', 'bgp')"
```

今回の例ではあまり意味は持ちませんが、下記のような書き方もできる為、大量のトリガー(テストケース)があったとしても`groups` を使って柔軟に実行対象を制御可能です。下記も両方実行されます。

```bash
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-groups "And('blitz', Or('snmp', 'bgp'))"
```

### トリガー(テストケース)の名前で実行したい

トリガー(テストケース)の名前で実行したい場合は、`--trigger-groups`の代わりに`--trigger-uids`を使います。

```bash
(genie_env)$ genie run --testbed-file tb.yaml --trigger-file trigger_datafile.yaml --trigger-uids "TriggerBlitsConfigureSnmpCommunity"
```

# まとめ

pyATS|Genie の Blitz でのネットワーク自動化のご紹介でしたが、どうでしたでしょうか？

冒頭で書いた悩みに対する`Blitz`の回答を入れてみました。

1. いつも python の知識が要求される **-> YAML のみで書ける**
2. 自動化ツールのベンダ毎のモジュールを覚えないといけない **-> pyATS|Genie 特に Blitz では4項目の使い方のみ**
3. せっかく覚えた CLI ベースの知識を生かしたい -> **pyATS|Genie Blitz では今までの CLI 知識を活かせます! Parsed を使えば詳細なチェックも簡単!**
4. 古い機器や構成もせっかくなら自動化したい -> **pyATS|Genie なら SSH だけでなく telnet/serial console、踏み台経由のアクセス、CLI/Netconf/REST を用いて幅広く古い機器から新しいものまで対応可能**

`Blitz`を**隠れた必殺技**と言っているのは、**pyATS|Genie の醍醐味は python でコードを書くことで柔軟なネットワークの自動化ができるという点**です。お分かりのように、上で紹介した方法ではテスト前に既にコンフィグが存在しているかなどの確認項目はなく、そこは考慮して使う必要があります。

しかしながら、python の知識を習得するまでの使い方としては `Blitz` のような使い方をマスターし、pyATS|Genie の使い方に触れ、python を使った高度なネットワーク自動化を pyATS|Genie で加速していけるのではないかと思います。

pyATS|Genie はますます進化しておりますので、今後にも乞うご期待です。機能追加のアイデアやフィードバック/改善点などありしたら、pyats-support-ext(at)cisco.com (英語)か私の @tahigash3 (日本語も可)までどうぞ気軽にご連絡ください。(Twitterも同じアカウント名 @tahigash3 です)

# 参考リンク

- [pyATS Document](https://developer.cisco.com/docs/pyats/api/)
- [Genie Document](https://developer.cisco.com/docs/genie-docs/)
  - [Genie CLI - Genie Run](https://pubhub.devnetcloud.com/media/genie-docs/docs/cli/genie_run.html)
- [Genie API Browser](https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/)

# 免責事項

本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。