pyATS/Genieから多段踏み台経由でNW機器へログインする

# はじめに
Ciscoが公開しているPythonベースのテスト自動化ソリューション「pyATS/Genie」を使い、複数の踏み台経由でNW機器へログインする方法をメモしておきます。


踏み台無しの場合や、1つの踏み台経由の場合は、別の方が詳しく説明されていますので割愛します。
[pyATS/Genie:踏み台を経由したネットワーク機器への接続](https://ccieojisan.net/post-1908/)


# テスト構成
pyATS/Genie(v22.2)をインストールした`CentOS`から、`Ubuntu` ⇒ `csr1000v-0(IOS-XE)` ⇒ `nxos9000-0(NX-OS)` 経由で`iosvl2-2(IOS)`へログインする構成としました。
プロトコルはSSHとTelnetを交互に使っています。（こんな構成無いでしょうけど。。。）
![20220305_1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310082/5ae894db-389c-a7a3-0ef3-382e9888f131.png)


# Testbed
今回作成したTestbedファイルは以下の通りです。各機器のログイン情報に加え、最終的なログイン機器の中で経由機器とログインコマンドを記載しています。（踏み台が1つの場合は、経由機器だけ記載すればOKです。）

```yaml:testbed_jumphost4.yaml
testbed:
  name: lab_test01
devices:
  # 1段目の踏み台
  ubuntu-0:
    os: linux
    type: linux
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      cli:
        protocol: ssh
        ip: 192.168.200.100
  # 2段目の踏み台
  csr1000v-0:
    os: iosxe
    type: router
    series: csr1000v
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      defaults:
        class: unicon.Unicon
      a:
        protocol: telnet
        ip: 192.168.200.150
  # 3段目の踏み台
  nxos9000-0:
    os: nxos
    type: switch
    series: n9k
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      defaults:
        class: unicon.Unicon
      a:
        protocol: ssh
        ip: 10.2.1.1
  # 最終的なログイン機器
  iosvl2-2:
    os: ios
    type: switch
    series: iosv
    credentials:
      default:
        username: cisco
        password: cisco
    connections:
      defaults:
        class: unicon.Unicon
      a:
        protocol: telnet
        ip: 10.3.1.3
        # 経由機器とログインコマンドを記載
        proxy:
          # 1段目の踏み台
          - device: ubuntu-0
            command: ssh cisco@192.168.100.150
          # 2段目の踏み台
          - device: csr1000v-0
            command: telnet 10.2.1.1
          # 3段目の踏み台
          - device: nxos9000-0
            command: ssh cisco@10.3.1.3
```

# Pythonコード
`iosvl2-2`にログインし、`show version`を実行の上、パース(構文解析)した結果を出力してみます。

```python:pyats1-1.py
from genie.testbed import load
from pprint import pprint

testbed = load('testbed_jumphost4.yaml')   # Testbedを指定
device = testbed.devices['iosvl2-2']   # ログイン機器を指定

# 今回は初期コマンド(no logging consoleやterminal width 511等)の実行を無効化
device.connect(init_exec_commands=[], init_config_commands=[])

output = device.parse('show version')
pprint(output)
```

# 実行結果

- 1段目の踏み台ログイン

```
$ python pyats1-1.py 
2022-03-05 21:15:47,905: %UNICON-INFO: +++ iosvl2-2 logfile /tmp/iosvl2-2-cli-20220305T211547904.log +++
2022-03-05 21:15:47,906: %UNICON-INFO: +++ Unicon plugin ios/iosv +++
2022-03-05 21:15:47,909: %UNICON-INFO: connection via proxy ubuntu-0
2022-03-05 21:15:47,912: %UNICON-INFO: +++ connection to spawn: ssh -l cisco 192.168.200.100, id: 140549527182976 +++
2022-03-05 21:15:47,913: %UNICON-INFO: connection to ubuntu-0
cisco@192.168.200.100's password: 
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-66-generic x86_64)
（省略）
cisco@ubuntu-0:~$ 
```

- 2段目の踏み台ログイン

```
2022-03-05 21:15:48,735: %UNICON-INFO: +++ initializing handle +++
2022-03-05 21:15:48,736: %UNICON-INFO: connection via proxy csr1000v-0
2022-03-05 21:15:48,805: %UNICON-INFO: connection to csr1000v-0
ssh cisco@192.168.200.150
Password: 
csr1000v-0>
2022-03-05 21:15:49,335: %UNICON-INFO: +++ initializing handle +++
enable
Password: 
csr1000v-0#
```

- 3段目の踏み台ログイン

```
2022-03-05 21:15:49,482: %UNICON-INFO: connection via proxy nxos9000-0
2022-03-05 21:15:49,529: %UNICON-INFO: connection to nxos9000-0
telnet 10.2.1.1
Trying 10.2.1.1 ... Open
User Access Verification
login: cisco
Password: 
Cisco NX-OS Software
Copyright (c) 2002-2020, Cisco Systems, Inc. All rights reserved.
（省略）
nxos9000-0# 
```

- 最終的なログイン、コマンド実行

```
2022-03-05 21:15:53,585: %UNICON-INFO: +++ initializing handle +++
2022-03-05 21:15:53,644: %UNICON-INFO: connection to iosvl2-2
ssh cisco@10.3.1.3
protocol identification string lack carriage return
Outbound-ReKey for 10.3.1.3:22
Inbound-ReKey for 10.3.1.3:22
（省略）
Password: 
（省略）
iosvl2-2>
2022-03-05 21:15:54,291: %UNICON-INFO: +++ initializing handle +++
enable
Password: 
iosvl2-2#
2022-03-05 21:15:56,220: %UNICON-INFO: +++ iosvl2-2 with via 'a': executing command 'show version' +++
show version
Cisco IOS Software, vios_l2 Software (vios_l2-ADVENTERPRISEK9-M), Experimental Version 15.2(20200924:215240) 
（省略）
iosvl2-2#
{'version': {'chassis': 'IOSv',
　　　　　　　 （省略）
             'system_image': 'flash0:/vios_l2-adventerprisek9-m',
             'uptime': '9 hours, 22 minutes',
             'version': '15.2(20200924:215240)',
             'version_short': '15.2'}}
```


# 参考URL

- [Getting Started with pyATS > Basic Concepts > Device Connection](https://pubhub.devnetcloud.com/media/pyats-getting-started/docs/quickstart/manageconnections.html#device-connection)
- [Connection Through Proxies — Unicon Documentation - DevNet](https://pubhub.devnetcloud.com/media/unicon/docs/user_guide/proxy.html#connection-through-proxies)