昨日寝ぼけて、pyatsのシナリオを書こうとしていたフォルダをrm -rfしちゃいました。というわけでtestbed.yamlから作り直ししたのでその作業記録です。

pyatsのインストール

ちょっと前にやっていたので、忘れてしまいました。historyを辿ると、

python3 -m pip install genie 'pyats[full]'

で何も考えず多分入れたと思います。

公式ドキュメントによるとvenvの利用が推奨らしいです。

$ mkdir pyats
$ cd pyats
$ python3 -m venv .
$ source bin/activate .
(pyats)$

pyATS/Genie: インストールとアップグレードのお話によると、 pip install pyats[full] rest.connector yang.connectorがおすすめのようです。

pyatsのtestbed.yamlの設定

testbed.yaml配下のように作りました。ip: に続くIPアドレスは皆さんの環境に合わせて適当(適切)に書いてください。 credentials以下のusernameとpasswordはSONiCの標準のままです。環境に合わせて適当(適切)に書いてください。 osは適切なものがなくlinuxにしています。

testbed:
  name: sonic-testbed

devices:
  sonic-vs1:
    os: linux
    connections:
      ssh:
        protocol: ssh
        ip: 任意
    credentials:
      default:
        username: admin
        password: YourPaSsWoRd

pyatsの内部で動く接続用のlibraryであるuniconの公式ドキュメントのSupported Platformsによると、osのlinuxの配下に、platformがないのでplatformは空欄にしています。 但しpyats validate testbedをするとWarningを言われます。ですが問題なく動きます

pyats validate testbed testbed.yaml

出力結果:

Loading testbed file: testbed.yaml
--------------------------------------------------------------------------------

Testbed Name:
    sonic-testbed

Testbed Devices:
.
`-- sonic-vs1 [linux]

YAML Lint Messages
------------------

Warning Messages
----------------
 - Device 'sonic-vs1' missing 'platform' definition
 - Device 'sonic-vs1' has no interface definitions

私のようにconnectionsconnectionとsを抜かして動かないと時間を溶かしたりとか、 credentialscredentialとsを抜かして動かないと時間を溶かしたりとかをpyats validate testbedでエラーを出してくれるので事前にやりましょう。

connectionsconnectionと書き間違えている場合。“connections"のキーワードがないと警告してくれる。

Loading testbed file: testbed.yaml
--------------------------------------------------------------------------------

YAML Lint Messages
------------------

Errors
------
 - Missing keys:
  "connections"  parent: [devices.sonic-vs1] (testbed.yaml line:9 column:3)

credentialscredentialと書き間違えている場合。“credentials"のキーワードがないと警告してくれる。

Loading testbed file: testbed.yaml
--------------------------------------------------------------------------------

YAML Lint Messages
------------------

Errors
------
 - ['devices', 'sonic-vs1']: Unsupported keys:
  "credential" (testbed.yaml line:15 column:5)

でもcredentials以下のdefaultdefualtuaを入れ替えて書いても警告してくれません。文法的には正しいからでしょう。おかげで指定した通りadmin/YourPaSsWoRd (SONiCのデフォルトのusernameとpassword) でログインされず、何故?と時間を溶かしました。

genie shellを使った接続

さて、正しいtestbed.yamlが準備できたら、早速接続してみましょう

 genie shell --testbed-file testbed.yaml

とすると、

Welcome to pyATS Interactive Shell                                                                                                                                                                               ==================================                                                             Python 3.8.10 (default, Mar 13 2023, 10:26:41)
[GCC 9.4.0]
>>> from pyats.topology.loader import load
>>> testbed = load('testbed.yaml') -------------------------------------------------------------------------------
>>>

こんな出力結果が帰ってくると思いますのでプロンプト(>>>)に

testbed.devices['sonic-vs1'].connect()

とデバイス名を指定して、connect()すると、

2023-04-09 11:54:24,824: %UNICON-INFO: +++ sonic-vs1 logfile /tmp/sonic-vs1-cli-20230409T115424823.log +++

2023-04-09 11:54:24,825: %UNICON-INFO: +++ Unicon plugin linux (unicon.plugins.linux) +++

2023-04-09 11:54:24,829: %UNICON-INFO: +++ connection to spawn: ssh -l admin 192.168.255.3, id: 140480106366384 +++

2023-04-09 11:54:24,829: %UNICON-INFO: connection to sonic-vs1
admin@192.168.255.3's password:
Linux sonic 5.10.0-18-2-amd64 #1 SMP Debian 5.10.140-1 (2022-09-02) x86_64
You are on
  ____   ___  _   _ _  ____
 / ___| / _ \| \ | (_)/ ___|
 \___ \| | | |  \| | | |
  ___) | |_| | |\  | | |___
 |____/ \___/|_| \_|_|\____|

-- Software for Open Networking in the Cloud --

Unauthorized access and/or use are prohibited.
All access and/or use are subject to monitoring.

Help:    https://sonic-net.github.io/SONiC/

Last login: Sat Apr  8 22:55:13 2023 from 192.168.255.2
admin@sonic:~$

2023-04-09 11:54:25,223: %UNICON-INFO: +++ initializing handle +++
"\radmin@192.168.255.3's password: \r\nLinux sonic 5.10.0-18-2-amd64 #1 SMP Debian 5.10.140-1 (2022-09-02) x86_64\r\nYou are on\r\n  ____   ___  _   _ _  ____\r\n / ___| / _ \\| \\ | (_)/ ___|\r\n \\___ \\| | | |  \\| | | |\r\n  ___) | |_| | |\\  | | |___\r\n |____/ \\___/|_| \\_|_|\\____|\r\n\r\n-- Software for Open Networking in the Cloud --\r\n\r\nUnauthorized access and/or use are prohibited.\r\nAll access and/or use are subject to monitoring.\r\n\r\nHelp:    https://sonic-net.github.io/SONiC/\r\n\r\nLast login: Sat Apr  8 22:55:13 2023 from 192.168.255.2\r\r\nadmin@sonic:~$ \n"

の様な出力が出てつながります。 一度そのままの出力を出した後にpyatsがparseしようとした結果を出そうとしていますね。

任意のコマンド実行

uniconの公式ドキュメントのSupported Platformsによると、

# Example
# -------
#
#   using the above testbed yaml file in pyATS

from pyats.topology import loader

testbed = loader.load('my-testbed.yaml')

device = testbed.devices['csr1000v-1']

device.connect()

device.execute('show version')

と書いてあり、connectで接続、executeで任意コマンドの実行してそうに見えます。というわけで、testbed.devices['デバイス名'].execute('コマンド名')で、任意のコマンドが実行できるようです。

>>> testbed.devices['sonic-vs1'].execute('show interface status') 

こんな感じで応答が返ってきました。

2023-04-09 12:00:05,471: %UNICON-INFO: +++ sonic-vs1 with via 'ssh': executing command 'show interface status' +++
show interface status
  Interface            Lanes    Speed    MTU    FEC           Alias    Vlan    Oper    Admin    Type    Asym PFC
-----------  ---------------  -------  -----  -----  --------------  ------  ------  -------  ------  ----------
  Ethernet0      25,26,27,28      40G   9100    N/A    fortyGigE0/0  routed    down       up     N/A         N/A
  Ethernet4      29,30,31,32      40G   9100    N/A    fortyGigE0/4  routed    down       up     N/A         N/A
  Ethernet8      33,34,35,36      40G   9100    N/A    fortyGigE0/8  routed    down       up     N/A         N/A
 Ethernet12      37,38,39,40      40G   9100    N/A   fortyGigE0/12  routed    down       up     N/A         N/A
 Ethernet16      45,46,47,48      40G   9100    N/A   fortyGigE0/16  routed    down       up     N/A         N/A
 Ethernet20      41,42,43,44      40G   9100    N/A   fortyGigE0/20  routed    down       up     N/A         N/A
 Ethernet24          1,2,3,4      40G   9100    N/A   fortyGigE0/24  routed    down       up     N/A         N/A
 Ethernet28          5,6,7,8      40G   9100    N/A   fortyGigE0/28  routed    down       up     N/A         N/A
 Ethernet32      13,14,15,16      40G   9100    N/A   fortyGigE0/32  routed    down       up     N/A         N/A
 Ethernet36       9,10,11,12      40G   9100    N/A   fortyGigE0/36  routed    down       up     N/A         N/A
 Ethernet40      17,18,19,20      40G   9100    N/A   fortyGigE0/40  routed    down       up     N/A         N/A
 Ethernet44      21,22,23,24      40G   9100    N/A   fortyGigE0/44  routed    down       up     N/A         N/A
 Ethernet48      53,54,55,56      40G   9100    N/A   fortyGigE0/48  routed    down       up     N/A         N/A
 Ethernet52      49,50,51,52      40G   9100    N/A   fortyGigE0/52  routed    down       up     N/A         N/A
 Ethernet56      57,58,59,60      40G   9100    N/A   fortyGigE0/56  routed    down       up     N/A         N/A
 Ethernet60      61,62,63,64      40G   9100    N/A   fortyGigE0/60  routed    down       up     N/A         N/A
 Ethernet64      69,70,71,72      40G   9100    N/A   fortyGigE0/64  routed    down       up     N/A         N/A
 Ethernet68      65,66,67,68      40G   9100    N/A   fortyGigE0/68  routed    down       up     N/A         N/A
 Ethernet72      73,74,75,76      40G   9100    N/A   fortyGigE0/72  routed    down       up     N/A         N/A
 Ethernet76      77,78,79,80      40G   9100    N/A   fortyGigE0/76  routed    down       up     N/A         N/A
 Ethernet80  109,110,111,112      40G   9100    N/A   fortyGigE0/80  routed    down       up     N/A         N/A
 Ethernet84  105,106,107,108      40G   9100    N/A   fortyGigE0/84  routed    down       up     N/A         N/A
 Ethernet88  113,114,115,116      40G   9100    N/A   fortyGigE0/88  routed    down       up     N/A         N/A
 Ethernet92  117,118,119,120      40G   9100    N/A   fortyGigE0/92  routed    down       up     N/A         N/A
 Ethernet96  125,126,127,128      40G   9100    N/A   fortyGigE0/96  routed    down       up     N/A         N/A
Ethernet100  121,122,123,124      40G   9100    N/A  fortyGigE0/100  routed    down       up     N/A         N/A
Ethernet104      81,82,83,84      40G   9100    N/A  fortyGigE0/104  routed    down       up     N/A         N/A
Ethernet108      85,86,87,88      40G   9100    N/A  fortyGigE0/108  routed    down       up     N/A         N/A
Ethernet112      93,94,95,96      40G   9100    N/A  fortyGigE0/112  routed    down       up     N/A         N/A
Ethernet116      89,90,91,92      40G   9100    N/A  fortyGigE0/116  routed    down       up     N/A         N/A
Ethernet120  101,102,103,104      40G   9100    N/A  fortyGigE0/120  routed    down       up     N/A         N/A
Ethernet124     97,98,99,100      40G   9100    N/A  fortyGigE0/124  routed    down       up     N/A         N/A
admin@sonic:~$
'  Interface            Lanes    Speed    MTU    FEC           Alias    Vlan    Oper    Admin    Type    Asym PFC\r\n-----------  ---------------  -------  -----  -----  --------------  ------  ------  -------  ------  ----------\r\n  Ethernet0      25,26,27,28      40G   9100    N/A    fortyGigE0/0  routed    down       up     N/A         N/A\r\n  Ethernet4      29,30,31,32      40G   9100    N/A    fortyGigE0/4  routed    down       up     N/A         N/A\r\n  Ethernet8      33,34,35,36      40G   9100    N/A    fortyGigE0/8  routed    down       up     N/A         N/A\r\n Ethernet12      37,38,39,40      40G   9100    N/A   fortyGigE0/12  routed    down       up     N/A         N/A\r\n Ethernet16      45,46,47,48      40G   9100    N/A   fortyGigE0/16  routed    down       up     N/A         N/A\r\n Ethernet20      41,42,43,44      40G   9100    N/A   fortyGigE0/20  routed    down       up     N/A         N/A\r\n Ethernet24          1,2,3,4      40G   9100    N/A   fortyGigE0/24  routed    down       up     N/A         N/A\r\n Ethernet28          5,6,7,8      40G   9100    N/A   fortyGigE0/28  routed    down       up     N/A         N/A\r\n Ethernet32      13,14,15,16      40G   9100    N/A   fortyGigE0/32  routed    down       up     N/A         N/A\r\n Ethernet36       9,10,11,12      40G   9100    N/A   fortyGigE0/36  routed    down       up     N/A         N/A\r\n Ethernet40      17,18,19,20      40G   9100    N/A   fortyGigE0/40  routed    down       up     N/A         N/A\r\n Ethernet44      21,22,23,24      40G   9100    N/A   fortyGigE0/44  routed    down       up     N/A         N/A\r\n Ethernet48      53,54,55,56      40G   9100    N/A   fortyGigE0/48  routed    down       up     N/A         N/A\r\n Ethernet52      49,50,51,52      40G   9100    N/A   fortyGigE0/52  routed    down       up     N/A         N/A\r\n Ethernet56      57,58,59,60      40G   9100    N/A   fortyGigE0/56  routed    down       up     N/A         N/A\r\n Ethernet60      61,62,63,64      40G   9100    N/A   fortyGigE0/60  routed    down       up     N/A         N/A\r\n Ethernet64      69,70,71,72      40G   9100    N/A   fortyGigE0/64  routed    down       up     N/A         N/A\r\n Ethernet68      65,66,67,68      40G   9100    N/A   fortyGigE0/68  routed    down       up     N/A         N/A\r\n Ethernet72      73,74,75,76      40G   9100    N/A   fortyGigE0/72  routed    down       up     N/A         N/A\r\n Ethernet76      77,78,79,80      40G   9100    N/A   fortyGigE0/76  routed    down       up     N/A         N/A\r\n Ethernet80  109,110,111,112      40G   9100    N/A   fortyGigE0/80  routed    down       up     N/A         N/A\r\n Ethernet84  105,106,107,108      40G   9100    N/A   fortyGigE0/84  routed    down       up     N/A         N/A\r\n Ethernet88  113,114,115,116      40G   9100    N/A   fortyGigE0/88  routed    down       up     N/A         N/A\r\n Ethernet92  117,118,119,120      40G   9100    N/A   fortyGigE0/92  routed    down       up     N/A         N/A\r\n Ethernet96  125,126,127,128      40G   9100    N/A   fortyGigE0/96  routed    down       up     N/A         N/A\r\nEthernet100  121,122,123,124      40G   9100    N/A  fortyGigE0/100  routed    down       up     N/A         N/A\r\nEthernet104      81,82,83,84      40G   9100    N/A  fortyGigE0/104  routed    down       up     N/A         N/A\r\nEthernet108      85,86,87,88      40G   9100    N/A  fortyGigE0/108  routed    down       up     N/A         N/A\r\nEthernet112      93,94,95,96      40G   9100    N/A  fortyGigE0/112  routed    down       up     N/A         N/A\r\nEthernet116      89,90,91,92      40G   9100    N/A  fortyGigE0/116  routed    down       up     N/A         N/A\r\nEthernet120  101,102,103,104      40G   9100    N/A  fortyGigE0/120  routed    down       up     N/A         N/A\r\nEthernet124     97,98,99,100      40G   9100    N/A  fortyGigE0/124  routed    down       up     N/A         N/A'

簡易的なparser作りに挑戦

なんだかgenie-parsegenというのを使うと、parserが簡単に作れるらしく、かつテーブル形式だと非常に簡単にParseできそうというのをドキュメント読んだたら気づきました。

ぱっとみheaderの配列だけ作ってあげれば動きそう。というわけで、やってみた。

>>> header = ['Interface', 'Lanes', 'Speed', 'MTU', 'FEC', 'Alias', 'Vlan', 'Oper', 'Admin', 'Type', 'Asym PFC'] 
>>> import re
>>> from pprint import pprint
>>> from genie.testbed import load
>>> from genie import parsergen
>>> output = testbed.devices['sonic-vs1'].execute('show interface status')
>>> result = parsergen.oper_fill_tabular(device_output=output, device_os='linux', header_fields=header, index=[0])
>>> pprint(result.entries)

出力結果(が長すぎるので先頭のみ抜粋)が以下

{'Ethernet0      25,26,': {'Admin': 'up',
                           'Alias': 'gE0/0  ro',
                           'Asym PFC': 'N/A',
                           'FEC': 'N/A    fortyGi',
                           'Interface': 'Ethernet0      25,26,',
                           'Lanes': '27,28',
                           'MTU': '100',
                           'Oper': 'down',
                           'Speed': '40G   9',
                           'Type': 'N/A',
                           'Vlan': 'uted'},
 'Ethernet100  121,122,12': {'Admin': 'up',
                             'Alias': '0/100  ro',
                             'Asym PFC': 'N/A',
                             'FEC': 'N/A  fortyGigE',
                             'Interface': 'Ethernet100  121,122,12',
                             'Lanes': '3,124',
                             'MTU': '100',
                             'Oper': 'down',
                             'Speed': '40G   9',
                             'Type': 'N/A',
                             'Vlan': 'uted'},

これは惜しい。一瞬いい感じに見えましたが、Interfaceの区切り位置が違って一部Laneの情報を含めてしまっています。Speedも一部MTUの出力とっちゃってますね。というわけでちゃんとparserを書かないといけないようです。今日はここまで。