【Sier,情シス向け】showコマンド取得作業を簡単に自動化してみよう！【pyATS】

# ネットワークエンジニアリングの悩み
**ステータス確認を複数の機器で実施したい時**
- 100n台に対して事前事後のステータス確認を行わないといけない => 作業対象x2倍の作業量が発生してしまう
- 作業台数が増えれば増えるほど作業不備のおそれが増大
    - ノード一台だけ取り忘れてしまって再度リモート接続申請、みたいな。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/37a0ce2f-e2b9-91a6-88d5-ecbcde5adf6d.png)

=>これ、**pyATS**という半オープンソースソフトウェアで簡単に自動化できます。Linuxの操作ができる方なら誰でも利用可能です。本記事では、実際に導入する中で出会った知見を織り込みながらSierや情シスの方にフォーカスしたpyATSのご紹介をしたいと思います。

## 自己紹介(2024/12時点)
- Sierでネットワークの設計構築やってます。
- 詳細設計書作成更新や投入コンフィグ作成、機器作業の自動化実績があります。
- Python3がちょっと書けます。


## そもそもpyATSとは？
正式名称：Python Automated Test System
- Ciscoが自社向けに開発していたテスト用ソフトウェア。現在は一部オープンソース化しており誰でも利用可能
- Python書けなくても自動化可能
- VM(Linux)やWSL2,コンテナ上で稼働可能(後述しますがVMでの展開をお勧めします)
- SSHやTelnetで機器へ接続しに行く事が可能
- 踏み台も対応
- 元々テスト用のツールなのでshowコマンド取得の他、各種試験やコンフィグ,ステータスの差分出力等も自動化可能

https://developer.cisco.com/docs/pyats/introduction/#cisco-pyats-network-test--automation-solution

## 実際何を実現できたの？
- Ciscoスイッチ100n台分の事前,事後ログ取得等の作業自動化
- 事前,事後での差分出力全自動化
- 他ユーザ学習用システムで発生する定期的な結合試験自動化

## pyATSセットアップ
公式作業手順: 

https://developer.cisco.com/docs/pyats-getting-started/

### 用意する環境
- 業務用Windows端末
- VMware workstation Pro(無料化しました)

学習コストが比較的低く、同一環境の展開が容易なのでVMを用いることをお勧めします。
pyATS展開オプションとしては他にWSL2やdockerが挙げられるのですが、WSL2とは違い、VMでの展開はVMをクローンしてしまえば他のエンジニアも簡単に同じ環境を利用できるので、Sierや情シスにお勧めです。展開の簡易性でいえばdockerも挙げられるのですが、こちらはそもそもdockerの建付けを学ばないといけません。自動化したいだけなのに環境の学習コストが上がってしまいますし、VMと比べdockerに関わるエンジニアの方は比率として少ないと思いますので、本記事ではVM版で記載したいと思います。

### 1.VMの用意
記事作成時点でpyATSは以下のプラットフォームをサポートしています。
- (社内) Cisco Enterprise Linux (CEL) 6.7+ (CLVS、ADS、ラボ CEL サーバーを含む)
- Ubuntu 14以降
- CentOS 6以降

VMからNATでホストPCのIPを用いてネットワークへ出られる事を確認してください。
問題なければpyATSをデプロイしたVMよりping (ホストPCのデフォルトゲートウェイ宛)コマンドが通るはずです。

また、Python3.7 ~ 3.10が利用できることも確認してください。

### 2.pyATSのインストール
venvは利用しない環境で記載したいと思います。VMなのでpyATS専用機として利用する想定でよいと思います。
1.以下コマンドを実行してpyATSをインストールします 
```Python3
pip install "pyats[full]"
```

2.以下コマンドを実行してpyATSが正常にインストールできているか確認します
特にエラーを吐くことなく、なんとなく以下のような出力が確認できると思います。
```Python3
pyats version check
You are currently running pyATS version: 21.4
Python: 3.6.8 [64bit]

  Package                      Version
  ---------------------------- -------
  genie                        21.4
  genie.libs.clean             21.4
  genie.libs.conf              21.4
  genie.libs.filetransferutils 21.4
  genie.libs.health            21.4.2
  genie.libs.ops               21.4
  genie.libs.parser            21.4
  genie.libs.robot             21.4
  genie.libs.sdk               21.4.1
  genie.telemetry              21.4
  genie.trafficgen             21.4
  pyats                        21.4
  pyats.aereport               21.4
  pyats.aetest                 21.4
  pyats.async                  21.4
  pyats.connections            21.4
  pyats.contrib                21.4
  pyats.datastructures         21.4
  pyats.easypy                 21.4
  pyats.kleenex                21.4
  pyats.log                    21.4
  pyats.reporter               21.4
  pyats.results                21.4
  pyats.robot                  21.4
  pyats.tcl                    21.4
  pyats.topology               21.4
  pyats.utils                  21.4
  unicon                       21.4
  unicon.plugins               21.4
```

3.Ciscoのmock環境を用いてpyATSの動作確認

```Python3
git clone https://github.com/CiscoTestAutomation/examples
pyats run job examples/basic/basic_example_job.py
```

特にエラー無く完了できれば、pyATSのセットアップは完了です。

4.(オプション)VScodeでのSSHセットアップ
Tera TermやVM ConsoleのCLIは見にくいので、VSCodeでVMへSSH=>VScode上からのVM操作もお勧めします。

## pyATSでコンフィグ取得を自動化してみよう！
### 練習構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/5fd89871-3847-c5b3-2ce9-17d02a618a77.png)

### 1. ノード定義ファイルの作成
まずyamlファイルで自動化したいnode情報を記載してあげる必要があります。ファイル名は何でも大丈夫ですが、慣習的に"testbed.yaml"とします。以下はサンプルです。
```testbed.yaml
devices:
  SW01:
    os: "iosxe"
    platform: cat3k
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      cli:
        protocol: ssh
        ip: "192.168.1.11"
        arguments:
          init_config_commands: []

  SW02:
    os: "iosxe"
    platform: cat3k
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      cli:
        protocol: ssh
        ip: "192.168.1.22"
        arguments:
          init_config_commands: []
```
**os&platform**
 => どのOSで稼働しているのか/どの製品シリーズで稼働しているのか記載する項目です。記載するとpyATSが個別に定義されているエラーハンドリングや出力待機をしてくれるようになります。
どれをサポートしていてどのような名称で記載できるのかは以下の公式Matrixをご参照ください。(pyATS公式github=>"Unicon"というプラグインのフォルダ構成からも情報を得られます)

https://pubhub.devnetcloud.com/media/unicon/docs/user_guide/supported_platforms.html

**credentials**
 =>機器へSSH接続する際に利用するクレデンシャル情報を記載する項目です。パスワード部分は暗号化することもできます。

**connections**
 => 機器への接続方法、機器のIP情報などを定義可能です。サンプルではssh接続に必要な情報のみを記載しておりますが、この他Telnet等も利用可能です。
 
:::note info
argumentsセクションに'init_config_commands: []'と記載するとpyATSのコンフィグ自動投入を実質無効化できるのでオススメです。
:::

上記の構成定義を自動化したいホスト分行う必要があります。結構な台数あると定義も大変ですが、pyATSではcsvファイルを用いて生成する事も可能です。
(ソースコードを見る限りまだカラム定義が少なく、argumentsセクションを定義出来なかったり使い勝手はあまりよろしくないですが...)


### 2. pyATS CLIコマンドの実行
後は以下のコマンドを実行するだけです。先に定義したtestbed.yamlと同じ階層にいることを確認してください。

~~~bash
pyats learn config --testbed-file testbed.yaml --single-process --device SW01 SW02 --output HOGE/MOGE
~~~
**--testbed-file \<filename\>**
使用したいノード定義ファイルを指定します。

**--single-process(任意)**
並列ではなく、一台ずつshow running-configコマンドを実行していきます。VM側の処理を軽くしたり、トラフィック量を少しでも減らしたい場合にお勧めです。但し、SSH等のリモート接続機能(unicon)に関してはログ取得前に動き、まず全機器へ繋ぎにいってしまうのでそこは要注意です。
例)20台が自動化対象の場合：まず20台全てにSSH接続=>次にshowコマンドを取得（並列or単一）

**--device(任意)**
指定したノード定義ファイルの中で接続しに行きたい(自動化したい)ノードのホスト名を指定します。ただこちらは指定しなくても大丈夫ですが、その場合pyATSはノード定義ファイルに記載されている全ノードへ接続しに行きます。
=> この動きを利用して、各拠点毎にノード定義ファイルを作成->拠点毎にpyATSで自動化(ノード指定要らず)みたいなことも実現可能です。

**--output(任意)**
取得したログを格納するフォルダを指定します。この例だとHOGE配下のMOGEフォルダ以下へ接続時のログ,show running-configログがそれぞれ全台分格納されるようなイメージです。

### 3.確認
HOGE/MOGEへcdしlsコマンドを叩くと、以下のファイルが確認できると思います。
```bash
connection_SW01.txt
connection_SW02.txt
config_iosxe_SW01_console.txt
config_iosxe_SW01_ops.txt
config_iosxe_SW02_console.txt
config_iosxe_SW02_ops.txt
```
**connectonファイル**
connection_.+.txtで各ノード分出力されています。pyATSがuniconプラグインを用いて機器へSSH接続を行った際のログが確認できます。また、接続確認としてpyATSが自動で実行した'show version'ログも確認できます。

**configファイル(console)**
末尾にconsoleと付与されているファイルです。'show running-config'コマンドの実行結果がそのまま出力されています。機器コンフィグの取得業務ではこちらを拾い上げる形になります。

**configファイル(ops)**
末尾にopsと付与されているファイルです。showコマンドの結果がJson形式で出力されています。pyATSで設定値の差異を出力する際や、試験自動化で各showコマンドの詳細なパラメータを指定する際に利用します。とりあえず残しておきましょう。

以上でコンフィグ取得の自動化は完了です！実際やってみるとpyATSのシンプルさに驚くと思います。

## pyATSでコンフィグ以外のshowコマンド取得を自動化してみよう！
pyATSでのshowコマンド取得方法には3つオプションがあります。'pyats learn', 'genie learn'といったpyatsの包括的な機能学習機能を用いて取得するか、'pyats parse', 'genie parse'といったpyATS のParserを動かすついでで取得するか、Pythonスクリプトを用いて取得するかのどちらかです。それぞれ立ち位置やコマンドの違いは以下となっております。
### ▽'pyats learn' or 'genie learn'コマンド
- pyATSで定義されている各機能毎によく参照されるコマンド群を包括的に取得することができます。(pyats learn ospfと入力するとospfに関するコマンドの幾つかを勝手に取得してくれる、といった具合です。)
- 取得するshowコマンドをpyATS側で定義されてしまっているので、あまり柔軟性は高くありません。
- 真下で説明しているParserとしての動きも取得するコマンド毎にやってくれてます。
- ホスト/コマンドの結果毎にファイルが生成されるので結構な量が吐き出されます。
- 後述のparserではshow runの取得ができないので、configだけ取得したいときはこっち使ってます。
```bash
よく使う形
pyats learn ospf --testbed-file testbed.yaml --single-process --output HOGE/MOGE | tee HOGE/MOGE/terminal_yyyymmdd.log
```
leanerが定義されている機能一覧はコチラから参照できます！

https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/models

### ▽'pyats parse' or 'genie parse'コマンド
- pyATS本来のユースケースである試験自動化のため、取得したshowコマンドの結果内容を細かく分解するための機能です。(Parserと表現されています)
- Json形式で細かく結果を分類したopsファイルを出力してくれるので、Python自動化でとても役に立ちます！(例: 取得した全台分のshow cdp neighborsからIFと対向ホスト名だけ吸い出して全ポート表へ反映とか)
- 取得したいshowコマンドについて、pyATS側でParserが定義されていないとエラーを吐いてしまいます。
- ホスト/コマンドの結果毎にファイルが生成されるので結構な量が吐き出されます。
- 自動化の素材としてログが欲しい時に使ってます。
```bash
よく使う形
pyats parse "show ip interface brief" "show ip interface" "show interfaces" "show logging" "show cdp neighbors" --testbed-file testbed.yaml --single-process --output HOGE/MOGE | tee HOGE/MOGE/terminal_yyyymmdd.log
```
Parserが存在しているコマンド一覧はコチラから参照できます！

https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/parsers

::: note info
歴史的な事情から、pyatsとgenieコマンドで二系存在しています。現在はpyatsコマンドで統一する方向で開発が進んでいるので、pyatsコマンドの方を利用する形でOKです。pyATSについて調べる際、よく旧体形のgenieコマンドとも遭遇すると思います。
:::

### ▽Pythonスクリプトでの取得
- Parserがあるないに関係なく、欲しいshowコマンドは全てこちらから取得可能です。
- 取得したいshowコマンドを全て定義しておいて、作業の事前事後ログの取得自動化でつかってます。
- 上記2つとは異なりホスト毎にファイルが生成されるので、1ファイルあたりの行数がかなり長くなります。1つのログファイルあたり1コマンドが良いのか、全コマンドが良いのか上長やお客様のお好みに合わせてParserと使い分けできる場合があります。
- 参考スクリプト置いておくので、是非使ってください！

```script.py
#よく使ってるスクリプト
from genie.testbed import load

commands = '''
show clock
ter len 0
show version
show env all
show users
show license all
show running-config
show vlan
show ip interface brief
show interface
show interface status
show udld
show inventory raw
show cdp neighbor
show ntp associations
show ntp status
show clock
show storm-control
show storm-control broadcast
show storm-control multicast
show errdisable detect
show errdisable recovery
show processes cpu sorted | exclude 0.00
show processes cpu history
show logging
show interfaces counters errors
show clock
'''

# device指定したいときはこんな感じで定義してあげる
target_devices = ["SW01","SW01"]

tb = load("testbed.yaml")

for device in target_devices: #もし全台対象とするなら'target_devices'を'tb.devices'に置き換える
    target = tb.devices[device] 
    target.connect()
    target.execute(commands, error_pattern=[])
    target.disconnect()

```

上記スクリプトを'python3 script.py | tee HOGE/MOGE/terminal_yyyymmdd.log'という具合に実行してあげる形です。**実行後のログは/tmpに全ホスト分格納されています(重要)**<=これ最初気づかなくて、ピーキーな機能だなとか思ったりしてました...

target.executeという箇所で'error_pattern=[]'という引数を指定しているのですが、これを指定することで、InvalidやAmbiguousエラーを無視してコマンド実行を続けることができるようになります。pyATSはエラーを検知すると後続の処理を停止してしまうので、iosやiosxe等、複数os分のshowコマンドを纏めたい！コマンド入力エラーが出ても無視してコマンドを取得したい！という場合は必須の引数になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/d6ae262c-0ff9-dde4-e819-932eb9eb58b1.png)
↑ iosxeでpyATSが定義してくれているエラーパターンです。これを上書きしてあげているイメージです。

https://github.com/CiscoTestAutomation/unicon.plugins

## pyATSでログ差分出力を自動化しよう！
pyats parseやlearnで取得したopsファイル群を用いて、ログ差分を出力できます。
差分が出ているホストの差分となっている箇所のみしてくれるので、ファイルが生成されている==以前と差分が出ていると簡単に理解することができます。

```bash
pyats diff <folder1> <folder2> --output HOGE/ROGE
```

## おわりに
この業界は如何にして物量業務を高品質・高速化できるかが勝負だと思います。常に挑戦し続けないと一生仕事が終わりません。さらにはどれだけ頑張っても、人間が取り組む以上確実に品質低下があります(物量業務は尚更)。無料で簡単に利用できるpyATSで、まずは5台分だけでも自動化を初めてみませんか？もし貴方がチームリーダーだったとして、一度自動化してしまえばメンバーへの引継ぎも簡単ですし高品質化も見込めるはずです。物量業務を自動化で捌いて空いた思考リソースを知的業務へどんどん割り当てていきましょう！


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