RADKit + Python によるネットワーク機器操作の自動化

## はじめに
これは、CiscoSystems 合同会社社員有志による AdventCalendar (2024年)の記事の一つです。  


https://qiita.com/advent-calendar/2024/cisco


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


## やりたいこと
この記事では、CiscoSystems が無料で提供しているトラブルシューティングツールである「 RADKit 」と Python スクリプトを使用して、遠隔から一部操作の自動化を目指します。RADKit の概要は下記記事をご覧ください。仕組みとしては、クラウド上に中間サーバ (RADKit Connector) があり、そちらへ RADKit Service / Client が TLS 接続を確立して、End-to-End でのアクセス経路を作り出すものとなります。サーバ/ストレージディスクが壊れたらサポートへ自動通知するといったサービスが他社ベンダー様にもあるかと思いますが、そのようなサービスと似たような仕組みになります。  


https://community.cisco.com/t5/-/-/ta-p/5018592


この記事では、具体的に下記を実現してみます。  
・RADKit を使って自宅からインターネット越しにミッドタウン東京 (CiscoSystems 合同会社の東京本社ビル) 内のラボにある Catalyst 8000v へリモートアクセスする。  
・その上で、以下操作を行う Python スクリプトを作成し、一部操作の自動化を実装してみる。  
 1) show tech の自動取得  
 2) IOSd/IOS-XE 各プロセスの CPU / メモリ使用率のリアルタイムモニタリング  
 3) インターフェースのリアルタイムモニタリング  

ではやっていきましょう！  


## 全体図
本記事の全体図は以下の通りとなります。  
(RADKit Client の脇に置かれているのは、、、まさか酒・・？？)  

![diagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/ab18b794-c9f6-c36b-6f0e-4fb69852f77d.jpeg)

■ 機器リスト  
・RADKit Client : Windows 11  
・RADKit Service / Clients : Ubuntu 24.04.01  
・Routers : Catalyst 8000v 17.12.4


Catalyst 8000v (以降 c8kv と表記) 間は BGP で経路交換をしています。(BGP を使っている理由は特にありません。使った方がなんとなくネットワークエンジニアっぽく見えるかなと)  
また非現実的と理解していますが、RADKit Service (以降 service と表記) は c8kv のルーティングトラフィックが流れるインターフェース越しにアクセスする構成としています。(RADKit 利用における制限等によるものではありません。シンプルに mgmt 用ネットワークの作成をサボっただけ・・)

私の自宅に RADKit Client (以降 client と表記) がインストールされた端末があり、192.168.100.0 のネットワークに service が動作するサーバが設置されています。私の自宅のインターネットから service が動作するサーバを介して、各 c8kv へリモートアクセスする構成です。  

段階をおって 1 つずつ環境を作成していきます。  

## 手順

client / service の作り方は下記マニュアルをベースにしています。  

https://radkit.cisco.com/docs/index.html


### 1. RADKit Client のインストール
まずは client のインストールを行います。
client / service ともに以下のリンクからソフトウェアをダウンロードできます。  

https://radkit.cisco.com/downloads/release/

現時点の Latest である 1.7.5 の Windows 用インストールソフトウェア「cisco_radkit_1.7.5_win64_signed.exe」をダウンロードして実行します。client のインストールは非常に簡単で、EXE ファイルをダブルクリックし、ウィザードに従ってインストールを進めることで完了します。  
インストールが完了すると、「RADKit Network Console」というアプリケーションが端末内に表示されるようになります。  

### 2. RADKit Service のインストール
client と同様に service のインストールを行います。 
インストール対象サーバは Ubuntu のため、Linux Installer を使ったインストール、または Python pip を使用したインストールのいずれかが選択できます。  
ここでは、Python pip を使った方法でインストールします。  

まずは Python 仮想環境の作成から。(pip は既にインストール済の前提です)  

<details>
<summary> Python 仮想環境の作成ログ </summary>

```
radkit@radkit:~$ python3 -V
Python 3.12.3

radkit@radkit:~$ sudo apt install python3-12-venv
radkit@radkit:~$ python3 -m venv radkit
radkit@radkit:~$ ll

drwxr-x--- 5 radkit radkit 4096 Dec  2 06:20 ./
drwxr-xr-x 3 root   root   4096 Nov 29 03:05 ../
-rw------- 1 radkit radkit   18 Nov 29 08:09 .ampcli
-rw------- 1 radkit radkit  240 Dec  2 03:50 .bash_history
-rw-r--r-- 1 radkit radkit  220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 radkit radkit 3771 Mar 31  2024 .bashrc
drwx------ 2 radkit radkit 4096 Nov 29 05:21 .cache/
-rw-r--r-- 1 radkit radkit  807 Mar 31  2024 .profile
drwxrwxr-x 5 radkit radkit 4096 Dec  2 06:20 radkit/　　　<<<< 作成した仮想環境名
drwx------ 2 radkit radkit 4096 Nov 29 07:19 .ssh/

radkit@radkit:~$ source radkit/bin/activate              <<<< 作成した仮想環境の有効化
(radkit) radkit@radkit:~$ 

(radkit) radkit@radkit:~$ python3 -V
Python 3.12.3
```

</details>

<br>

続いて、ソフトウェアダウンロードサイトから「 cisco_radkit_1.7.5_pip_linux_x86.tgz 」をダウンロードしてサーバへ SCP などでアップロードし、作成済の Python 仮想環境上へ pip を使って service をインストールします。  

<details>
<summary> service のインストールログ </summary>

```
(radkit) radkit@radkit:~$ mkdir wheels_dir        <<<< ソフトウェア格納先の作成

### SFTP でアップロード中・・・ 

(radkit) radkit@radkit:~$ ll wheels_dir
total 202248
drwxrwxr-x 2 radkit radkit      4096 Dec  2 06:39 ./
drwxr-x--- 6 radkit radkit      4096 Dec  2 06:39 ../
-rw-rw-r-- 1 radkit radkit 207093591 Dec  2  2024 cisco_radkit_1.7.5_pip_linux_x86.tgz

(radkit) radkit@radkit:~$ tar zxvf wheels_dir/cisco_radkit_1.7.5_pip_linux_x86.tgz -C wheels_dir
./
cisco_radkit_client-1.7.5-cp39-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
cisco_radkit_service-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
cisco_radkit_genie-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp311-none-manylinux1_x86_64.whl
cisco_radkit_genie-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
cisco_radkit_client-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
cisco_radkit_client-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
cisco_radkit_genie-1.7.5-cp38-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp312-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
cisco_radkit_service-1.7.5-cp39-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp310-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
cisco_radkit_service-1.7.5-cp311-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp312-none-manylinux1_x86_64.whl
cisco_radkit_genie-1.7.5-cp310-none-manylinux1_x86_64.whl
cisco_radkit_common-1.7.5-cp39-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp310-none-manylinux1_x86_64.whl
cisco_radkit_genie-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
cisco_radkit_genie-1.7.5-cp312-none-manylinux1_x86_64.whl
cisco_radkit_genie-1.7.5-cp311-none-manylinux1_x86_64.whl
cisco_radkit_genie-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
cisco_radkit_genie-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
cisco_radkit_service-1.7.5-cp38-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
cisco_radkit_genie-1.7.5-cp39-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
cisco_radkit_client-1.7.5-cp38-none-manylinux1_x86_64.whl
cisco_radkit_common-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp312-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp38-none-manylinux1_x86_64.whl
cisco_radkit_client-1.7.5-cp311-none-manylinux1_x86_64.whl
cisco_radkit_service-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
cisco_radkit_common-1.7.5-cp310-none-manylinux1_x86_64.whl

(radkit) radkit@radkit:~$ ll wheels_dir
total 405716
drwx------ 2 radkit radkit      4096 Nov 19 12:50 ./
drwx------ 6 radkit radkit      4096 Dec  2 06:41 ../
-rw-rw-r-- 1 radkit radkit 207093591 Dec  2  2024 cisco_radkit_1.7.5_pip_linux_x86.tgz
-rw-r--r-- 1 radkit radkit   6378324 Nov 19 12:48 cisco_radkit_client-1.7.5-cp310-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   6372711 Nov 19 12:45 cisco_radkit_client-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   7721524 Nov 19 12:48 cisco_radkit_client-1.7.5-cp311-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   7717499 Nov 19 12:45 cisco_radkit_client-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   7039617 Nov 19 12:48 cisco_radkit_client-1.7.5-cp312-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   7034000 Nov 19 12:45 cisco_radkit_client-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   6313002 Nov 19 12:48 cisco_radkit_client-1.7.5-cp38-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   6303231 Nov 19 12:45 cisco_radkit_client-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   6360612 Nov 19 12:48 cisco_radkit_client-1.7.5-cp39-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   6352822 Nov 19 12:45 cisco_radkit_client-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3730249 Nov 19 12:47 cisco_radkit_common-1.7.5-cp310-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3724939 Nov 19 12:44 cisco_radkit_common-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   5111566 Nov 19 12:47 cisco_radkit_common-1.7.5-cp311-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   5105265 Nov 19 12:44 cisco_radkit_common-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   4432468 Nov 19 12:47 cisco_radkit_common-1.7.5-cp312-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   4426391 Nov 19 12:45 cisco_radkit_common-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3665736 Nov 19 12:47 cisco_radkit_common-1.7.5-cp38-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3654359 Nov 19 12:44 cisco_radkit_common-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3723080 Nov 19 12:47 cisco_radkit_common-1.7.5-cp39-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   3710507 Nov 19 12:44 cisco_radkit_common-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23496 Nov 19 12:48 cisco_radkit_genie-1.7.5-cp310-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23496 Nov 19 12:46 cisco_radkit_genie-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23497 Nov 19 12:48 cisco_radkit_genie-1.7.5-cp311-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23496 Nov 19 12:46 cisco_radkit_genie-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23496 Nov 19 12:48 cisco_radkit_genie-1.7.5-cp312-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23497 Nov 19 12:46 cisco_radkit_genie-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23495 Nov 19 12:48 cisco_radkit_genie-1.7.5-cp38-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23498 Nov 19 12:45 cisco_radkit_genie-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23495 Nov 19 12:48 cisco_radkit_genie-1.7.5-cp39-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit     23498 Nov 19 12:45 cisco_radkit_genie-1.7.5-cp39-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9183294 Nov 19 12:47 cisco_radkit_service-1.7.5-cp310-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9177522 Nov 19 12:45 cisco_radkit_service-1.7.5-cp310-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit  11717621 Nov 19 12:47 cisco_radkit_service-1.7.5-cp311-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit  11715166 Nov 19 12:45 cisco_radkit_service-1.7.5-cp311-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit  10478555 Nov 19 12:48 cisco_radkit_service-1.7.5-cp312-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit  10464907 Nov 19 12:45 cisco_radkit_service-1.7.5-cp312-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9073780 Nov 19 12:47 cisco_radkit_service-1.7.5-cp38-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9059542 Nov 19 12:45 cisco_radkit_service-1.7.5-cp38-none-musllinux_1_1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9155773 Nov 19 12:47 cisco_radkit_service-1.7.5-cp39-none-manylinux1_x86_64.whl
-rw-r--r-- 1 radkit radkit   9144312 Nov 19 12:45 cisco_radkit_service-1.7.5-cp39-none-musllinux_1_1_x86_64.whl

### pip による service のインストール開始

(radkit) radkit@radkit:~$ python3 -m pip install -f wheels_dir cisco_radkit_service
Looking in links: wheels_dir
Processing ./wheels_dir/cisco_radkit_service-1.7.5-cp312-none-manylinux1_x86_64.whl
Processing ./wheels_dir/cisco_radkit_common-1.7.5-cp312-none-manylinux1_x86_64.whl (from cisco_radkit_service)
Collecting prompt-toolkit<4.0,>=3.0.48 (from cisco_radkit_service)
  Downloading prompt_toolkit-3.0.48-py3-none-any.whl.metadata (6.4 kB)
Collecting ptpython<4.0,>=3.0.22 (from cisco_radkit_service)
  Downloading ptpython-3.0.29-py2.py3-none-any.whl.metadata (11 kB)
Collecting pydantic==2.8.2 (from cisco_radkit_service)
  Downloading pydantic-2.8.2-py3-none-any.whl.metadata (125 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 125.2/125.2 kB 9.2 MB/s eta 0:00:00
Collecting email-validator>=2.0.0 (from cisco_radkit_service)
  Downloading email_validator-2.2.0-py3-none-any.whl.metadata (25 kB)
Collecting pydantic-settings>=2.3.4 (from cisco_radkit_service)
  Downloading pydantic_settings-2.6.1-py3-none-any.whl.metadata (3.5 kB)
Collecting fastapi>=0.100.0 (from cisco_radkit_service)
  Downloading fastapi-0.115.5-py3-none-any.whl.metadata (27 kB)
Collecting hypercorn<1.0,>=0.14.4 (from cisco_radkit_service)
  Downloading hypercorn-0.17.3-py3-none-any.whl.metadata (5.4 kB)
Collecting lxml<6.0,>=4.9.4 (from cisco_radkit_service)
  Downloading lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl.metadata (3.8 kB)
Collecting pyang!=2.6.0,<3.0,>=2.0 (from cisco_radkit_service)
  Downloading pyang-2.6.1-py2.py3-none-any.whl.metadata (821 bytes)
Collecting ncclient<0.6.16,>=0.6.12 (from cisco_radkit_service)
  Downloading ncclient-0.6.15.tar.gz (634 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 634.9/634.9 kB 47.0 MB/s eta 0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting asyncssh<3.0,>=2.14.2 (from asyncssh[pyopenssl]<3.0,>=2.14.2->cisco_radkit_service)
  Downloading asyncssh-2.18.0-py3-none-any.whl.metadata (9.9 kB)
Collecting xmltodict<1.0,>=0.13.0 (from cisco_radkit_service)
  Downloading xmltodict-0.14.2-py2.py3-none-any.whl.metadata (8.0 kB)
Collecting regex>=2019.6.5 (from cisco_radkit_service)
  Downloading regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (40 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.5/40.5 kB 6.6 MB/s eta 0:00:00
Collecting psutil<6.0,>=5.9.0 (from cisco_radkit_service)
  Downloading psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (21 kB)
Collecting PyYAML<7.0,>=6.0 (from cisco_radkit_service)
  Downloading PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)
Collecting httpx<1.0,>=0.23.0 (from cisco_radkit_service)
  Downloading httpx-0.28.0-py3-none-any.whl.metadata (7.1 kB)
Collecting httpcore>=1.0.4 (from cisco_radkit_service)
  Downloading httpcore-1.0.7-py3-none-any.whl.metadata (21 kB)
Collecting python-multipart<0.1.0,>=0.0.6 (from cisco_radkit_service)
  Downloading python_multipart-0.0.19-py3-none-any.whl.metadata (1.8 kB)
Collecting telnetlib3<3.0,>=2.0.0 (from cisco_radkit_service)
  Downloading telnetlib3-2.0.4-py2.py3-none-any.whl.metadata (7.1 kB)
Collecting aiohttp<4.0,>=3.9 (from cisco_radkit_service)
  Downloading aiohttp-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (7.7 kB)
Collecting multidict<7.0,>=4.5 (from cisco_radkit_service)
  Downloading multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.0 kB)
Collecting click!=8.1.0,!=8.1.4,!=8.1.5,<8.1.4,>=8.0.1 (from cisco_radkit_service)
  Downloading click-8.1.3-py3-none-any.whl.metadata (3.2 kB)
Collecting sqlalchemy==1.3.24 (from cisco_radkit_service)
  Downloading SQLAlchemy-1.3.24.tar.gz (6.4 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.4/6.4 MB 70.7 MB/s eta 0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting alembic==1.10.1 (from cisco_radkit_service)
  Downloading alembic-1.10.1-py3-none-any.whl.metadata (7.2 kB)
Collecting tacacs-plus==2.6 (from cisco_radkit_service)
  Downloading tacacs_plus-2.6-py2.py3-none-any.whl.metadata (1.1 kB)
Collecting pyzipper<0.4,>=0.3.6 (from cisco_radkit_service)
  Downloading pyzipper-0.3.6-py2.py3-none-any.whl.metadata (3.5 kB)
Collecting asyncinotify<5.0,>=4.0 (from cisco_radkit_service)
  Downloading asyncinotify-4.2.0-py3-none-any.whl.metadata (4.7 kB)
Collecting Mako (from alembic==1.10.1->cisco_radkit_service)
  Downloading Mako-1.3.6-py3-none-any.whl.metadata (2.9 kB)
Collecting typing-extensions>=4 (from alembic==1.10.1->cisco_radkit_service)
  Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting pydantic-settings>=2.3.4 (from cisco_radkit_service)
  Downloading pydantic_settings-2.3.4-py3-none-any.whl.metadata (3.3 kB)
Collecting cryptography<44.0,>=43.0.1 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl.metadata (5.4 kB)
Collecting pyte==0.8.2 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pyte-0.8.2-py3-none-any.whl.metadata (3.0 kB)
Collecting pytz>=2021.1 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pytz-2024.2-py2.py3-none-any.whl.metadata (22 kB)
Collecting anyio<4.5.0,>=4.4.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading anyio-4.4.0-py3-none-any.whl.metadata (4.6 kB)
Collecting exceptiongroup>=1.0.2 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading exceptiongroup-1.2.2-py3-none-any.whl.metadata (6.6 kB)
Collecting tomlkit<1.0,>=0.11.8 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading tomlkit-0.13.2-py3-none-any.whl.metadata (2.7 kB)
Collecting zstandard<1.0,>=0.19.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Collecting asn1<3.0,>=2.5.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading asn1-2.7.1-py2.py3-none-any.whl.metadata (5.8 kB)
Collecting pysnmp-lextudio<6.0,>=5.0.29 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pysnmp_lextudio-5.0.34-py3-none-any.whl.metadata (8.1 kB)
Collecting pysmi-lextudio!=1.3.4,!=1.4.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pysmi_lextudio-1.4.3-py3-none-any.whl.metadata (8.1 kB)
Collecting pyasn1!=0.6.1,<1.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pyasn1-0.6.0-py2.py3-none-any.whl.metadata (8.3 kB)
Collecting filelock<4.0,>=3.11 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading filelock-3.16.1-py3-none-any.whl.metadata (2.9 kB)
Collecting starlette<1.0,>=0.25.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading starlette-0.41.3-py3-none-any.whl.metadata (6.0 kB)
Collecting pyjwt<3.0,>=2.6 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading PyJWT-2.10.1-py3-none-any.whl.metadata (4.0 kB)
Collecting wsproto<1.3.0,>=0.14.0 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading wsproto-1.2.0-py3-none-any.whl.metadata (5.6 kB)
Collecting importlib-resources<7.0,>=6.1 (from cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading importlib_resources-6.4.5-py3-none-any.whl.metadata (4.0 kB)
Collecting annotated-types>=0.4.0 (from pydantic==2.8.2->cisco_radkit_service)
  Downloading annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB)
Collecting pydantic-core==2.20.1 (from pydantic==2.8.2->cisco_radkit_service)
  Downloading pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)
Collecting python-dotenv>=0.21.0 (from pydantic-settings>=2.3.4->cisco_radkit_service)
  Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)
Collecting six (from tacacs-plus==2.6->cisco_radkit_service)
  Downloading six-1.16.0-py2.py3-none-any.whl.metadata (1.8 kB)
Collecting wcwidth (from pyte==0.8.2->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading wcwidth-0.2.13-py2.py3-none-any.whl.metadata (14 kB)
Collecting aiohappyeyeballs>=2.3.0 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading aiohappyeyeballs-2.4.4-py3-none-any.whl.metadata (6.1 kB)
Collecting aiosignal>=1.1.2 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading aiosignal-1.3.1-py3-none-any.whl.metadata (4.0 kB)
Collecting attrs>=17.3.0 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading attrs-24.2.0-py3-none-any.whl.metadata (11 kB)
Collecting frozenlist>=1.1.1 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (13 kB)
Collecting propcache>=0.2.0 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (9.2 kB)
Collecting yarl<2.0,>=1.17.0 (from aiohttp<4.0,>=3.9->cisco_radkit_service)
  Downloading yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (69 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 69.2/69.2 kB 11.1 MB/s eta 0:00:00
Collecting pyOpenSSL>=23.0.0 (from asyncssh[pyopenssl]<3.0,>=2.14.2->cisco_radkit_service)
  Downloading pyOpenSSL-24.3.0-py3-none-any.whl.metadata (15 kB)
Collecting dnspython>=2.0.0 (from email-validator>=2.0.0->cisco_radkit_service)
  Downloading dnspython-2.7.0-py3-none-any.whl.metadata (5.8 kB)
Collecting idna>=2.0.0 (from email-validator>=2.0.0->cisco_radkit_service)
  Downloading idna-3.10-py3-none-any.whl.metadata (10 kB)
Collecting certifi (from httpcore>=1.0.4->cisco_radkit_service)
  Downloading certifi-2024.8.30-py3-none-any.whl.metadata (2.2 kB)
Collecting h11<0.15,>=0.13 (from httpcore>=1.0.4->cisco_radkit_service)
  Downloading h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)
Collecting h2>=3.1.0 (from hypercorn<1.0,>=0.14.4->cisco_radkit_service)
  Downloading h2-4.1.0-py3-none-any.whl.metadata (3.6 kB)
Collecting priority (from hypercorn<1.0,>=0.14.4->cisco_radkit_service)
  Downloading priority-2.0.0-py3-none-any.whl.metadata (6.6 kB)
Collecting setuptools>0.6 (from ncclient<0.6.16,>=0.6.12->cisco_radkit_service)
  Using cached setuptools-75.6.0-py3-none-any.whl.metadata (6.7 kB)
Collecting paramiko>=1.15.0 (from ncclient<0.6.16,>=0.6.12->cisco_radkit_service)
  Downloading paramiko-3.5.0-py3-none-any.whl.metadata (4.4 kB)
Collecting appdirs (from ptpython<4.0,>=3.0.22->cisco_radkit_service)
  Downloading appdirs-1.4.4-py2.py3-none-any.whl.metadata (9.0 kB)
Collecting jedi>=0.16.0 (from ptpython<4.0,>=3.0.22->cisco_radkit_service)
  Downloading jedi-0.19.2-py2.py3-none-any.whl.metadata (22 kB)
Collecting pygments (from ptpython<4.0,>=3.0.22->cisco_radkit_service)
  Downloading pygments-2.18.0-py3-none-any.whl.metadata (2.5 kB)
Collecting pycryptodomex (from pyzipper<0.4,>=0.3.6->cisco_radkit_service)
  Downloading pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.4 kB)
Collecting sniffio>=1.1 (from anyio<4.5.0,>=4.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading sniffio-1.3.1-py3-none-any.whl.metadata (3.9 kB)
Collecting enum-compat (from asn1<3.0,>=2.5.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading enum_compat-0.0.3-py3-none-any.whl.metadata (954 bytes)
Collecting cffi>=1.12 (from cryptography<44.0,>=43.0.1->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting hyperframe<7,>=6.0 (from h2>=3.1.0->hypercorn<1.0,>=0.14.4->cisco_radkit_service)
  Downloading hyperframe-6.0.1-py3-none-any.whl.metadata (2.7 kB)
Collecting hpack<5,>=4.0 (from h2>=3.1.0->hypercorn<1.0,>=0.14.4->cisco_radkit_service)
  Downloading hpack-4.0.0-py3-none-any.whl.metadata (2.5 kB)
Collecting parso<0.9.0,>=0.8.4 (from jedi>=0.16.0->ptpython<4.0,>=3.0.22->cisco_radkit_service)
  Downloading parso-0.8.4-py2.py3-none-any.whl.metadata (7.7 kB)
Collecting bcrypt>=3.2 (from paramiko>=1.15.0->ncclient<0.6.16,>=0.6.12->cisco_radkit_service)
  Downloading bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl.metadata (9.8 kB)
Collecting pynacl>=1.5 (from paramiko>=1.15.0->ncclient<0.6.16,>=0.6.12->cisco_radkit_service)
  Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl.metadata (8.6 kB)
Collecting Jinja2<4.0.0,>=3.1.3 (from pysmi-lextudio!=1.3.4,!=1.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting ply<4.0,>=3.11 (from pysmi-lextudio!=1.3.4,!=1.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading ply-3.11-py2.py3-none-any.whl.metadata (844 bytes)
Collecting requests<3.0.0,>=2.26.0 (from pysmi-lextudio!=1.3.4,!=1.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading requests-2.32.3-py3-none-any.whl.metadata (4.6 kB)
Collecting pyasyncore<2.0.0,>=1.0.0 (from pysnmp-lextudio<6.0,>=5.0.29->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pyasyncore-1.0.4-py3-none-any.whl.metadata (3.7 kB)
Collecting pysnmpcrypto<0.0.5,>=0.0.4 (from pysnmp-lextudio<6.0,>=5.0.29->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pysnmpcrypto-0.0.4-py2.py3-none-any.whl.metadata (2.4 kB)
Collecting MarkupSafe>=0.9.2 (from Mako->alembic==1.10.1->cisco_radkit_service)
  Downloading MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.0 kB)
Collecting pycparser (from cffi>=1.12->cryptography<44.0,>=43.0.1->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Collecting charset-normalizer<4,>=2 (from requests<3.0.0,>=2.26.0->pysmi-lextudio!=1.3.4,!=1.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (34 kB)
Collecting urllib3<3,>=1.21.1 (from requests<3.0.0,>=2.26.0->pysmi-lextudio!=1.3.4,!=1.4.0->cisco-radkit-common==1.7.5->cisco_radkit_service)
  Downloading urllib3-2.2.3-py3-none-any.whl.metadata (6.5 kB)
Downloading alembic-1.10.1-py3-none-any.whl (212 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 212.2/212.2 kB 29.8 MB/s eta 0:00:00
Downloading pydantic-2.8.2-py3-none-any.whl (423 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 423.9/423.9 kB 50.5 MB/s eta 0:00:00
Downloading pydantic_settings-2.3.4-py3-none-any.whl (22 kB)
Downloading tacacs_plus-2.6-py2.py3-none-any.whl (17 kB)
Downloading pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.1/2.1 MB 63.3 MB/s eta 0:00:00
Downloading pyte-0.8.2-py3-none-any.whl (31 kB)
Downloading aiohttp-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.7 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.7/1.7 MB 61.9 MB/s eta 0:00:00
Downloading asyncinotify-4.2.0-py3-none-any.whl (17 kB)
Downloading asyncssh-2.18.0-py3-none-any.whl (367 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 367.6/367.6 kB 46.3 MB/s eta 0:00:00
Downloading click-8.1.3-py3-none-any.whl (96 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 96.6/96.6 kB 20.2 MB/s eta 0:00:00
Downloading email_validator-2.2.0-py3-none-any.whl (33 kB)
Downloading fastapi-0.115.5-py3-none-any.whl (94 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 94.9/94.9 kB 18.6 MB/s eta 0:00:00
Downloading httpcore-1.0.7-py3-none-any.whl (78 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.6/78.6 kB 15.1 MB/s eta 0:00:00
Downloading httpx-0.28.0-py3-none-any.whl (73 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73.6/73.6 kB 15.0 MB/s eta 0:00:00
Downloading hypercorn-0.17.3-py3-none-any.whl (61 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.7/61.7 kB 11.9 MB/s eta 0:00:00
Downloading lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl (4.9 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.9/4.9 MB 65.8 MB/s eta 0:00:00
Downloading multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (131 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 131.0/131.0 kB 24.4 MB/s eta 0:00:00
Downloading prompt_toolkit-3.0.48-py3-none-any.whl (386 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 386.6/386.6 kB 48.4 MB/s eta 0:00:00
Downloading psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (288 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 288.2/288.2 kB 43.1 MB/s eta 0:00:00
Downloading ptpython-3.0.29-py2.py3-none-any.whl (67 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.1/67.1 kB 13.7 MB/s eta 0:00:00
Downloading pyang-2.6.1-py2.py3-none-any.whl (594 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 594.7/594.7 kB 57.7 MB/s eta 0:00:00
Downloading python_multipart-0.0.19-py3-none-any.whl (24 kB)
Downloading PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (767 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 767.5/767.5 kB 58.7 MB/s eta 0:00:00
Downloading pyzipper-0.3.6-py2.py3-none-any.whl (67 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.7/67.7 kB 15.1 MB/s eta 0:00:00
Downloading regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (796 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 796.9/796.9 kB 59.4 MB/s eta 0:00:00
Downloading telnetlib3-2.0.4-py2.py3-none-any.whl (93 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 93.3/93.3 kB 18.8 MB/s eta 0:00:00
Downloading xmltodict-0.14.2-py2.py3-none-any.whl (10.0 kB)
Downloading aiohappyeyeballs-2.4.4-py3-none-any.whl (14 kB)
Downloading aiosignal-1.3.1-py3-none-any.whl (7.6 kB)
Downloading annotated_types-0.7.0-py3-none-any.whl (13 kB)
Downloading anyio-4.4.0-py3-none-any.whl (86 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 86.8/86.8 kB 16.5 MB/s eta 0:00:00
Downloading asn1-2.7.1-py2.py3-none-any.whl (10 kB)
Downloading attrs-24.2.0-py3-none-any.whl (63 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.0/63.0 kB 11.3 MB/s eta 0:00:00
Downloading cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl (4.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.0/4.0 MB 68.9 MB/s eta 0:00:00
Downloading dnspython-2.7.0-py3-none-any.whl (313 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 313.6/313.6 kB 44.9 MB/s eta 0:00:00
Downloading exceptiongroup-1.2.2-py3-none-any.whl (16 kB)
Downloading filelock-3.16.1-py3-none-any.whl (16 kB)
Downloading frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (283 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 283.6/283.6 kB 41.5 MB/s eta 0:00:00
Downloading h11-0.14.0-py3-none-any.whl (58 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 58.3/58.3 kB 10.9 MB/s eta 0:00:00
Downloading h2-4.1.0-py3-none-any.whl (57 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.5/57.5 kB 11.0 MB/s eta 0:00:00
Downloading idna-3.10-py3-none-any.whl (70 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 70.4/70.4 kB 13.5 MB/s eta 0:00:00
Downloading importlib_resources-6.4.5-py3-none-any.whl (36 kB)
Downloading jedi-0.19.2-py2.py3-none-any.whl (1.6 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 66.3 MB/s eta 0:00:00
Downloading paramiko-3.5.0-py3-none-any.whl (227 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 227.1/227.1 kB 33.9 MB/s eta 0:00:00
Downloading propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (243 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 243.6/243.6 kB 39.0 MB/s eta 0:00:00
Downloading pyasn1-0.6.0-py2.py3-none-any.whl (85 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 85.3/85.3 kB 17.6 MB/s eta 0:00:00
Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB)
Downloading pyOpenSSL-24.3.0-py3-none-any.whl (56 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 56.1/56.1 kB 10.4 MB/s eta 0:00:00
Downloading pysmi_lextudio-1.4.3-py3-none-any.whl (83 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 83.7/83.7 kB 16.6 MB/s eta 0:00:00
Downloading pysnmp_lextudio-5.0.34-py3-none-any.whl (290 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 290.2/290.2 kB 40.8 MB/s eta 0:00:00
Downloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)
Downloading pytz-2024.2-py2.py3-none-any.whl (508 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 508.0/508.0 kB 44.2 MB/s eta 0:00:00
Using cached setuptools-75.6.0-py3-none-any.whl (1.2 MB)
Downloading starlette-0.41.3-py3-none-any.whl (73 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73.2/73.2 kB 16.0 MB/s eta 0:00:00
Downloading tomlkit-0.13.2-py3-none-any.whl (37 kB)
Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Downloading wsproto-1.2.0-py3-none-any.whl (24 kB)
Downloading yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (336 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 336.9/336.9 kB 45.0 MB/s eta 0:00:00
Downloading zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.4 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.4/5.4 MB 63.4 MB/s eta 0:00:00
Downloading appdirs-1.4.4-py2.py3-none-any.whl (9.6 kB)
Downloading certifi-2024.8.30-py3-none-any.whl (167 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 167.3/167.3 kB 29.4 MB/s eta 0:00:00
Downloading Mako-1.3.6-py3-none-any.whl (78 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.6/78.6 kB 16.5 MB/s eta 0:00:00
Downloading priority-2.0.0-py3-none-any.whl (8.9 kB)
Downloading pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.3/2.3 MB 63.5 MB/s eta 0:00:00
Downloading pygments-2.18.0-py3-none-any.whl (1.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 66.6 MB/s eta 0:00:00
Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Downloading wcwidth-0.2.13-py2.py3-none-any.whl (34 kB)
Downloading bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl (278 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 278.6/278.6 kB 43.3 MB/s eta 0:00:00
Downloading cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 479.4/479.4 kB 56.2 MB/s eta 0:00:00
Downloading hpack-4.0.0-py3-none-any.whl (32 kB)
Downloading hyperframe-6.0.1-py3-none-any.whl (12 kB)
Downloading jinja2-3.1.4-py3-none-any.whl (133 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.3/133.3 kB 25.3 MB/s eta 0:00:00
Downloading MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (23 kB)
Downloading parso-0.8.4-py2.py3-none-any.whl (103 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 103.7/103.7 kB 20.3 MB/s eta 0:00:00
Downloading ply-3.11-py2.py3-none-any.whl (49 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.6/49.6 kB 8.2 MB/s eta 0:00:00
Downloading pyasyncore-1.0.4-py3-none-any.whl (10 kB)
Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (856 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 kB 63.6 MB/s eta 0:00:00
Downloading pysnmpcrypto-0.0.4-py2.py3-none-any.whl (6.5 kB)
Downloading requests-2.32.3-py3-none-any.whl (64 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 64.9/64.9 kB 11.5 MB/s eta 0:00:00
Downloading sniffio-1.3.1-py3-none-any.whl (10 kB)
Downloading enum_compat-0.0.3-py3-none-any.whl (1.3 kB)
Downloading charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (143 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 kB 26.7 MB/s eta 0:00:00
Downloading urllib3-2.2.3-py3-none-any.whl (126 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.3/126.3 kB 24.9 MB/s eta 0:00:00
Downloading pycparser-2.22-py3-none-any.whl (117 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 kB 22.1 MB/s eta 0:00:00
Building wheels for collected packages: sqlalchemy, ncclient
  Building wheel for sqlalchemy (pyproject.toml) ... done
  Created wheel for sqlalchemy: filename=SQLAlchemy-1.3.24-cp312-cp312-linux_x86_64.whl size=1256380 sha256=a003db7f808d8b1ab91cacf77cdf2c2697729cc2d0ba3f09f55125669e618445
  Stored in directory: /home/radkit/.cache/pip/wheels/ea/86/24/26a773f9bd1cadef3007e8779dbe2a6ac1161fea92758ad924
  Building wheel for ncclient (pyproject.toml) ... done
  Created wheel for ncclient: filename=ncclient-0.6.15-py2.py3-none-any.whl size=88091 sha256=db48e49431e858112550979eea9a80d82b78eff9a1eb7a78e16a6580871e48b5
  Stored in directory: /home/radkit/.cache/pip/wheels/0a/00/87/c64461f0ef7f77c71a8447690102fdee93ff9725c516495de2
Successfully built sqlalchemy ncclient
Installing collected packages: wcwidth, pytz, pyasyncore, ply, enum-compat, appdirs, zstandard, xmltodict, urllib3, typing-extensions, tomlkit, telnetlib3, sqlalchemy, sniffio, six, setuptools, regex, PyYAML, python-multipart, python-dotenv, pyte, pyjwt, pygments, pycryptodomex, pycparser, pyasn1, psutil, propcache, prompt-toolkit, priority, parso, multidict, MarkupSafe, lxml, importlib-resources, idna, hyperframe, hpack, h11, frozenlist, filelock, exceptiongroup, dnspython, click, charset-normalizer, certifi, bcrypt, attrs, asyncinotify, asn1, annotated-types, aiohappyeyeballs, yarl, wsproto, tacacs-plus, requests, pyzipper, pydantic-core, pyang, Mako, Jinja2, jedi, httpcore, h2, email-validator, cffi, anyio, aiosignal, starlette, pysmi-lextudio, pynacl, pydantic, ptpython, hypercorn, httpx, cryptography, alembic, aiohttp, pysnmpcrypto, pyOpenSSL, pydantic-settings, paramiko, fastapi, asyncssh, pysnmp-lextudio, ncclient, cisco-radkit-common, cisco_radkit_service
Successfully installed Jinja2-3.1.4 Mako-1.3.6 MarkupSafe-3.0.2 PyYAML-6.0.2 aiohappyeyeballs-2.4.4 aiohttp-3.11.9 aiosignal-1.3.1 alembic-1.10.1 annotated-types-0.7.0 anyio-4.4.0 appdirs-1.4.4 asn1-2.7.1 asyncinotify-4.2.0 asyncssh-2.18.0 attrs-24.2.0 bcrypt-4.2.1 certifi-2024.8.30 cffi-1.17.1 charset-normalizer-3.4.0 cisco-radkit-common-1.7.5 cisco_radkit_service-1.7.5 click-8.1.3 cryptography-43.0.3 dnspython-2.7.0 email-validator-2.2.0 enum-compat-0.0.3 exceptiongroup-1.2.2 fastapi-0.115.5 filelock-3.16.1 frozenlist-1.5.0 h11-0.14.0 h2-4.1.0 hpack-4.0.0 httpcore-1.0.7 httpx-0.28.0 hypercorn-0.17.3 hyperframe-6.0.1 idna-3.10 importlib-resources-6.4.5 jedi-0.19.2 lxml-5.3.0 multidict-6.1.0 ncclient-0.6.15 paramiko-3.5.0 parso-0.8.4 ply-3.11 priority-2.0.0 prompt-toolkit-3.0.48 propcache-0.2.1 psutil-5.9.8 ptpython-3.0.29 pyOpenSSL-24.3.0 pyang-2.6.1 pyasn1-0.6.0 pyasyncore-1.0.4 pycparser-2.22 pycryptodomex-3.21.0 pydantic-2.8.2 pydantic-core-2.20.1 pydantic-settings-2.3.4 pygments-2.18.0 pyjwt-2.10.1 pynacl-1.5.0 pysmi-lextudio-1.4.3 pysnmp-lextudio-5.0.34 pysnmpcrypto-0.0.4 pyte-0.8.2 python-dotenv-1.0.1 python-multipart-0.0.19 pytz-2024.2 pyzipper-0.3.6 regex-2024.11.6 requests-2.32.3 setuptools-75.6.0 six-1.16.0 sniffio-1.3.1 sqlalchemy-1.3.24 starlette-0.41.3 tacacs-plus-2.6 telnetlib3-2.0.4 tomlkit-0.13.2 typing-extensions-4.12.2 urllib3-2.2.3 wcwidth-0.2.13 wsproto-1.2.0 xmltodict-0.14.2 yarl-1.18.3 zstandard-0.23.0
```

</details>

<br>

service のインストールが完了したら、service の管理ユーザー (superadmin) を作成します。  

<details>
<summary> superadmin の作成ログ </summary>

```
(radkit) radkit@radkit:~$ radkit-service bootstrap

06:49:24.211Z INFO  | internal | Logging configured [root_level=ERROR level=INFO con_level=TRACE con_json=False file_level=TRACE file_json=False file_name='/home/radkit/.radkit/logs/service/service.log' file_rotate=True with_rate_limiting=True]
06:49:24.211Z INFO  | internal | RADKit Service [version='1.7.5']
Set up the superadmin user. You'll be asked to provide a superadmin password.
Keep this password securely stored, as it will be impossible to recover it!
Superadmin password (for new setup): **********       <<<< password を設定
Confirm: **********                             
06:49:36.826Z INFO  | internal | Creating new database file. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
06:49:36.828Z INFO  | internal | Storing DB encryption key in credentials backend. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
06:49:36.934Z INFO  | internal | Storing DB secrets encryption key in credentials backend. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
06:49:37.041Z INFO  | internal | Opening database. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
06:49:37.042Z INFO  | internal | Database has been upgraded [schema_revision='0042-connection-modes-2024_09_27']
06:49:37.044Z INFO  | internal | Ensuring backup directory [backup_dir_path='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5']
06:49:37.044Z INFO  | internal | Backing up keys and certs files...
06:49:37.045Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/webserver.pem' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/webserver.pem']
06:49:37.045Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/webserver.key' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/webserver.key']
06:49:37.046Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/e2ee.pem' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/e2ee.pem']
06:49:37.046Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/e2ee.key' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/e2ee.key']
06:49:37.047Z INFO  | internal | Backing up database...
06:49:37.047Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/service-db.json.encrypted' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/service-db.json.encrypted-1.7.5-0042-connection-modes-2024_09_27']
06:49:37.048Z INFO  | internal | Backing up file [src='/home/radkit/.radkit/service/secrets.json' dst='/home/radkit/.radkit/service/backups/20241202-064937_1.7.5/secrets.json']
06:49:37.062Z INFO  | internal | Creating administrator [admin_name='superadmin']
06:49:37.065Z INFO  | internal | Database closed. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]

Bootstrapping is complete. The next step is to enroll with the RADKit Certificate Authority.
You can now start the Service with 'radkit-service run' and log on to the WebUI as 'superadmin'.
Alternatively, you can enroll through the CLI (see documentation for details).
```

</details>

<br>

その後、service を起動し、インストール処理は完了です。  

<details>
<summary> service の起動ログ </summary>

```
(radkit) radkit@radkit:~$ radkit-service --domain PROD run
08:06:17.825Z INFO  | internal | Logging configured [root_level=ERROR level=INFO con_level=TRACE con_json=False file_level=TRACE file_json=False file_name='/home/radkit/.radkit/logs/service/service.log' file_rotate=True with_rate_limiting=True]
08:06:17.825Z INFO  | internal | RADKit Service [version='1.7.5']
08:06:17.827Z INFO  | internal | This RADKit release does not expire
08:06:17.828Z INFO  | internal | Cisco Remote Automation Development Kit (RADKit) -- Copyright (c) 2018-2024 by Cisco Systems, Inc.

Cisco Online Privacy Statement: <https://www.cisco.com/c/en/us/about/legal/privacy-full.html>

The use of Cisco RADKit and the associated software and cloud services is governed by the Cisco End User License Agreement (EULA) available at: <https://www.cisco.com/c/en/us/about/legal/cloud-and-software/end_user_license_agreement.html>

For any additional questions regarding the use of this product, please contact `radkit@cisco.com`.

Certain third-party libraries used by Cisco RADKit are licensed under the GNU Lesser General Public License ("LGPL") version 2.1 or version 3, respectively, and come with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify the code for those libraries under the terms of their respective license. For more details, see either: the documentation bundled with Cisco RADKit; the online documentation at <https://radkit.cisco.com/>; or contact `radkit@cisco.com`.

For more information about the Open Source components used in this and other Cisco products, please refer to the Open Source portal at: <https://www.cisco.com/c/en/us/about/legal.html>

08:06:17.830Z INFO  | internal | Service lockfile created successfully 
Superadmin password: **********   [correct]       >>>> superadmin のパスワードを入力
08:06:22.382Z INFO  | internal | Opening database. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
08:06:22.460Z INFO  | internal | Creating service
08:06:22.463Z INFO  | internal | Starting RADKit Service [log_dir=PosixPath('/home/radkit/.radkit/logs/service')]
08:06:22.470Z INFO  | internal | Starting UI and API listener [addresses=['::'] secure_port=8081]
08:06:23.083Z INFO  | internal | Webserver certificate fingerprint [fingerprint='bdecefae822c5915179cb042b8973eee88d3b655c729c85dc7753937964b4ebb']
08:06:23.084Z INFO  | internal | E2EE certificate fingerprint [fingerprint='eb4b8277d1c7e53ddb328fdc58458c1f0db3c3611d72fa3697f3b0b683d71577']
08:06:23.124Z INFO  | internal | Starting RPC server [addresses=['0.0.0.0'] port=8181]
08:06:23.125Z INFO  | internal | Starting HTTP server [bind=[':::8081']]
08:06:23.183Z INFO  | internal | Running on https://[::]:8081 (CTRL + C to quit)
08:06:23.207Z INFO  | internal | Starting RPC server [addresses=['::'] port=8181]
 
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────| RADKit Service | Not connected to any domain | 1.7.5 | INFO | https://localhost:8081 |──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                                                                                                                                                                                                                                                           │
│                                                                                                                                            This RADKit release does not expire                                                                                                                                            │
│                                                                                                                                                                                                                                                                                                                           │
│                                                                                                                             Press Ctrl-C to shut down or Ctrl-F to show detailed information.                                                                                                                             │
│                                                                                                                          Press Ctrl-G to toggle the logging level between INFO, DEBUG and TRACE.             
```

</details>

<br>
<br>

::: note warn  
0.28.0 の httpx がインストールされている場合、service の起動に失敗してしまいます。別アプリケーションを対象とした話題ですが、以下が参考になります。  

https://github.com/geekan/MetaGPT/issues/1617

<details>
<summary> httpx 起因の service 起動失敗ログ </summary>

```
(radkit) radkit@radkit:~$ radkit-service run
07:38:34.644Z INFO  | internal | Logging configured [root_level=ERROR level=INFO con_level=TRACE con_json=False file_level=TRACE file_json=False file_name='/home/radkit/.radkit/logs/service/service.log' file_rotate=True with_rate_limiting=True]
07:38:34.645Z INFO  | internal | RADKit Service [version='1.7.5']
07:38:34.646Z INFO  | internal | This RADKit release does not expire
07:38:34.647Z INFO  | internal | Cisco Remote Automation Development Kit (RADKit) -- Copyright (c) 2018-2024 by Cisco Systems, Inc.

Cisco Online Privacy Statement: <https://www.cisco.com/c/en/us/about/legal/privacy-full.html>

The use of Cisco RADKit and the associated software and cloud services is governed by the Cisco End User License Agreement (EULA) available at: <https://www.cisco.com/c/en/us/about/legal/cloud-and-software/end_user_license_agreement.html>

For any additional questions regarding the use of this product, please contact `radkit@cisco.com`.

Certain third-party libraries used by Cisco RADKit are licensed under the GNU Lesser General Public License ("LGPL") version 2.1 or version 3, respectively, and come with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify the code for those libraries under the terms of their respective license. For more details, see either: the documentation bundled with Cisco RADKit; the online documentation at <https://radkit.cisco.com/>; or contact `radkit@cisco.com`.

For more information about the Open Source components used in this and other Cisco products, please refer to the Open Source portal at: <https://www.cisco.com/c/en/us/about/legal.html>

07:38:34.649Z INFO  | internal | Service lockfile created successfully 
Superadmin password: **********   [correct]
07:38:40.370Z INFO  | internal | Opening database. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
07:38:40.412Z INFO  | internal | Database closed. [path=PosixPath('/home/radkit/.radkit/service/service-db.json.encrypted')]
07:38:40.413Z INFO  | internal | Service lockfile removed successfully
07:38:40.414Z CRITI | internal | Terminating RADKit Service unexpectedly. [reason="AsyncClient.__init__() got an unexpected keyword argument 'proxies'"]
Traceback (most recent call last):
  File "/home/radkit/radkit/bin/radkit-service", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "<frozen radkit_service.entry_points.service>", line 27, in main
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/radkit/radkit/lib/python3.12/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen radkit_service.cli.service.commands.commands>", line 54, in wrapper
  File "<frozen radkit_service.cli.service.commands.commands>", line 647, in run
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "<frozen radkit_service.cli.service.commands._helpers>", line 507, in run_service
  File "<frozen radkit_service.start>", line 132, in run_service
  File "/usr/lib/python3.12/contextlib.py", line 659, in enter_async_context
    result = await _enter(cm)
             ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/contextlib.py", line 210, in __aenter__
    return await anext(self.gen)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<frozen radkit_service.service>", line 278, in get_default_runner_implementations
  File "/usr/lib/python3.12/contextlib.py", line 210, in __aenter__
    return await anext(self.gen)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<frozen radkit_service.runners.http_runner.implementations.httpx>", line 105, in create
  File "/home/radkit/radkit/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 790, in start
    return await future
           ^^^^^^^^^^^^
  File "<frozen radkit_service.runners.http_runner.implementations.httpx>", line 116, in _create_and_update_httpx_clients
  File "/usr/lib/python3.12/contextlib.py", line 210, in __aenter__
    return await anext(self.gen)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<frozen radkit_service.runners.http_runner.implementations.httpx>", line 177, in _create_httpx_clients
  File "<frozen radkit_service.runners.http_runner.implementations.httpx>", line 160, in create_client
TypeError: AsyncClient.__init__() got an unexpected keyword argument 'proxies'
```

</details>

<br>

起動できない問題が発生した場合、以下コマンドによって httpx のバージョンをダウングレードすることによって、回避することが可能です。

```
(radkit) radkit@radkit:~$ pip install httpx==0.27.2
```
:::
<br>

### 3. RADKit Service へのルータ登録

service の起動完了後、service の管理画面へアクセスし、c8kv へリモートアクセスするための設定を行います。Web ブラウザで「 https://<service の IP アドレス>:8081 」へアクセスし、service の管理画面へ先ほど作成した superadmin でログインします。  

![service-login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/98e0d585-3416-ddf7-97ca-44a974c238d4.jpeg)

<br>

ログイン後、メニューの connectivity をクリックし、Enroll with SSO をクリックします。  

![service-connectivity.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/f6574d3f-ba0b-0d3a-b031-f6d6aad58ae8.jpeg)

![service-connectivity-sso.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/bc4c7acb-2114-d202-4d8b-4dfcbb8e35b5.jpeg)

<br>

CCO に登録したメールアドレスを入力して Submit します。  

![service-connectivity-sso-submit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/6a94dc28-b159-526c-8226-11f316be53d1.jpeg)

<br>

RADKit Cloud へアクセスすることの承認画面が Web ブラウザ上に表示されるので、accept をクリックします。  
![service-connectivity-accept.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/12bef485-572b-d025-5713-60e9347a1f50.jpeg)

<br>

accept すると、下記のような画面が表示されます。これは閉じていただいて OK です。   

![service-connectivity-accept-done.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/50f557aa-cad7-a2ba-7b70-6e7d219f42e8.jpeg)

<br>

その後 SSO ログイン処理が走りますので、「 CLICK HERE 」リンクをクリックします。  

![service-connectivity-clickhere.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/9a32b5eb-3327-2123-266c-06b85a107459.jpeg)

<br>

その後しばらく経つと、Enroll 処理が完了しますので、Close をクリックします。  

![service-connectivity-ssodone.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/04f8f4d9-ccdc-ccc6-2267-74fe65e56a49.jpeg)

<br>

Enroll 処理が完了すると、画面上部に Service ID が表示されるようになります。 
client からのアクセス時に必要となるので、こちらの ID は控えておいてください。  

![service-serviceID.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/c52da275-8663-377e-6a9f-e6d5ffb23e21.jpeg)

<br>

次に Role Based Access Control (以降 RBAC と表記) の設定を行います。  
これは、Remote User がアクセス可能となる Device を Label を使って制限する機能となります。まずは RABC の有効化を行います。  

![service-rbac.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/275d3bd3-7185-1b62-f6c5-d4f2e20eac33.jpeg)

<br>

![service-rbac-enable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/41a9c44f-4cc7-4f85-25d9-4d9f61a07423.jpeg)

<br>

その後、「 + Add Label 」をクリックして任意の Label を作成します。  

![service-rbac-add-label.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/6d7af2c8-2e24-3155-a013-2716d89998fd.jpeg)

<br>

次に Remote User の登録を行います。  
メニューの Remote Users から「 + Add User 」をクリックし、CCO に登録したメールアドレスを入力後、各設定箇所をスクリーンショット通りクリックして「 Add & close」をクリックします。  

![service-add-user.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/34095885-7a95-dcea-0240-ea481854775a.jpeg)

![service-register-user.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/da73d662-ab78-4d75-bfd8-d865c51e50ea.jpeg)

<br>

最後にルータの登録を行います。  
メニューの Devices から「 + Add Device 」をクリックし、スクリーンショットの通り、ルータ名 / デバイスタイプ / (service から見た)接続先 IP アドレス / Lable / 接続方式とクレデンシャルを設定して「 Add & close」をクリックします。(スクリーンショットには c8kv-1 のものしかありませんが、実際には c8kv-2 も同様に登録を行っています)  

![service-add-device.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/573069c5-d623-6502-920c-3323f2569052.jpeg)

![service-register-device.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/a1fc8277-3d6f-6a2c-18c2-9a9cd6793125.jpeg)

<br>

### 4. 接続確認

service へのルータ登録完了後、client からリモートアクセスできるか試してみます。まず、RADKit Network Console を立ち上げ、ログイン処理を行います。  

<details>
<summary> client でのログイン処理 </summary>

```
[] > login dummy-user@cisco.com domain PROD         >>>> CCO ID でログイン
Logging in as: dummy-user@cisco.com on domain PROD

A browser window was opened to continue the authentication process. Please follow the instructions there.

Authentication result received.
[dummy-user] >                                      >>>> ログイン後、ユーザー名が表示される
```

</details>

<br>

ログイン後、Service ID 宛に接続し、登録したルータが Inventory に表示されるか確認します。  

<details>
<summary> service への接続と Inventory の確認 </summary>

```
[dummy-user] > service czes-xxxx-yyyy no-sr         >>>> Service ID へ接続
Connecting to Service: czes-xxxx-yyyy without SR context

[dummy-user@czes-xxxx-yyyy] > show inventory        >>>> 登録デバイスの確認
[READY] <radkit_client.sync.device.DeviceDict object at 0x215401614d0>
name    host            device_type    Terminal    Netconf    SNMP    Swagger    HTTP    description    failed

------  --------------  -------------  ----------  ---------  ------  ---------  ------  -------------  --------
c8kv-1  192.168.100.11  IOS_XE         True        False      False   False      False                  False
c8kv-2  192.168.100.12  IOS_XE         True        False      False   False      False                  False

Untouched inventory from service czes-xxxx-yyyy.

↑先ほど登録したルータが無事出力された
```

</details>

<br>

ルータへリモートログインできるか確認します。  
show version コマンドも実行できるので、正常にリモートログインできているようです。  

<details>
<summary> ルータへのリモートログイン確認 </summary>

```
[dummy-user@czes-xxxx-yyyy] > interactive c8kv-1       >>>> c8kv-1 へのログインコマンド

   Attaching to  c8kv-1  ...
     Type:  ~.  to detach.
            ~?  for other shortcuts.
   When using nested SSH sessions, add an extra  ~  per level of nesting.

Warning: all sessions are logged. Never type passwords or other secrets, except at an echo-less password prompt.


c8k-1#
c8k-1#
c8k-1#
c8k-1#show ver
Cisco IOS XE Software, Version 17.12.04
Cisco IOS Software [Dublin], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 17.12.4, RELEASE SOFTWARE (fc3)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2024 by Cisco Systems, Inc.
Compiled Tue 23-Jul-24 09:44 by mcpre


Cisco IOS-XE software, Copyright (c) 2005-2024 by cisco Systems, Inc.
All rights reserved.  Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0.  The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0.  For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.


ROM: IOS-XE ROMMON

c8k-1 uptime is 4 days, 1 hour, 17 minutes
Uptime for this control processor is 4 days, 1 hour, 18 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: Unknown reason



This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.

A summary of U.S. laws governing Cisco cryptographic products may be found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

If you require further assistance please contact us by sending email to
export@cisco.com.

License Level:
License Type: Perpetual
Next reload license Level:

Addon License Level:
Addon License Type: Subscription
Next reload addon license Level:

The current throughput level is 20000 kbps


Smart Licensing Status: Smart Licensing Using Policy

cisco C8000V (VXE) processor (revision VXE) with 2030522K/3075K bytes of memory.
Processor board ID 90H7JGKSXIA
Router operating mode: Autonomous
2 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
3960196K bytes of physical memory.
11526144K bytes of virtual hard disk at bootflash:.

Configuration register is 0x2102

c8k-1#
```

</details>

<br>

ようやくリモートログインできる環境が整いました。  
では、ネットワーク機器操作の自動化実装に入ります！  

### 5. Python スクリプトの準備

::: note info  
client での処理を Python で自動化するためには、 Windows 11 の端末にあらかじめ Python がインストールされていることを前提としています。また、Windows 11 の端末に pip を使って RADKit Client がインストールされていることが前提となります。(インストールファイル名は「cisco_radkit_1.7.5_pip_win.tgz」となります)  
:::

まずはテストを兼ねて以下のサンプルスクリプトを実行してみます。  
これは、入力された email と service ID を使って service へアクセスして inventory を表示し、inventory 内の指定した機器に対して任意のコマンドを実行するスクリプトとなります。  

<details>
<summary> サンプルスクリプト </summary>

```python:sample.py
from radkit_client.sync import Client

def script(client: Client) -> None:
    email = input("enter your email address:")
    serviceid = input("enter service id:")
    client.sso_login(identity=email,domain="PROD")
    service = client.service_cloud(serviceid).wait()
    print(service.inventory)

    dev = input("enter device name you want to access:")
    command = input("enter command:")

    req = service.inventory[dev].exec(command).wait()
    print(req.result.data)


def main():
    with Client.create() as client:
        script(client)

if __name__ == "__main__":
    main()
```

</details>

<br>

実際に Windows 11 のコマンドプロンプトから実行した結果は下記の通りです。  


<details>
<summary> サンプルスクリプトの実行結果 </summary>

```
C:\Users\xxxxx>python radkit-test.py
enter your email address:xxxxx@cisco.com
enter service id:czes-xxxx-xxxx

A browser window was opened to continue the authentication process. Please follow the instructions there.   >>>> このタイミングで Web ブラウザに service アクセスの accept 画面が自動表示される

Authentication result received.   >>>> Web ブラウザで accept すると表示され、以降の処理が走る

[READY] <radkit_client.sync.device.DeviceDict object at 0x21eb165de10>
name    host            device_type    Terminal    Netconf    SNMP    Swagger    HTTP    description    failed

------  --------------  -------------  ----------  ---------  ------  ---------  ------  -------------  --------
c8kv-1  192.168.100.11  IOS_XE         True        False      False   False      False                  False
c8kv-2  192.168.100.12  IOS_XE         True        False      False   False      False                  False

Untouched inventory from service czes-xxxx-xxxx.
enter device name you want to access:c8kv-1    >>>> ルータを指定する
enter command:show ver    >>>> ルータで実行するコマンドを指定する

### ルータとコマンドを指定すると、その実行結果が出力される

c8k-1#show ver
Cisco IOS XE Software, Version 17.12.04
Cisco IOS Software [Dublin], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 17.12.4, RELEASE SOFTWARE (fc3)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2024 by Cisco Systems, Inc.
Compiled Tue 23-Jul-24 09:44 by mcpre


Cisco IOS-XE software, Copyright (c) 2005-2024 by cisco Systems, Inc.
All rights reserved.  Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0.  The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0.  For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.


ROM: IOS-XE ROMMON

c8k-1 uptime is 5 days, 59 minutes
Uptime for this control processor is 5 days, 1 hour, 0 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: Unknown reason



This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.

A summary of U.S. laws governing Cisco cryptographic products may be found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

If you require further assistance please contact us by sending email to
export@cisco.com.

License Level:
License Type: Perpetual
Next reload license Level:

Addon License Level:
Addon License Type: Subscription
Next reload addon license Level:

The current throughput level is 20000 kbps


Smart Licensing Status: Smart Licensing Using Policy

cisco C8000V (VXE) processor (revision VXE) with 2030522K/3075K bytes of memory.
Processor board ID 90H7JGKSXIA
Router operating mode: Autonomous
2 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
3960196K bytes of physical memory.
11526144K bytes of virtual hard disk at bootflash:.

Configuration register is 0x2102

c8k-1#
```

</details>

<br>

では、上記のサンプルスクリプトをカスタマイズして、c8kv に対して以下のような処理を行うスクリプトを作成してみたいと思います。  

1) スクリプトを起動すると、まず email / service ID の入力を求める。  
2) 入力後、以下のメニューを出力する。  
 ・show tech の自動取得  
 ・IOSd/IOS-XE 各プロセスの CPU / メモリ使用率のリアルタイムモニタリング   
 ・インターフェースのリアルタイムモニタリング  
 ・何もせずに Exit  
3) メニューを選んだタイミングで service へ接続して inventory を表示し、どのルータに対して処理を行うかの入力を求める。  
4) 指定したルータに対して指定した処理の実行を行い、終了する。  

出来上がったスクリプトは以下となります。  
それでは実行してみましょう！！！

<details>
<summary> 完成したスクリプト </summary>

```python:automation.py
from radkit_client.sync import Client
import questionary
import sys
import os
import datetime
import time

email = ""
serviceid = ""

# service 接続
def service_attach(client: Client) -> None:
    global email
    global serviceid
    client.sso_login(identity=email,domain="PROD")
    service = client.service_cloud(serviceid).wait()
    print(service.inventory)
    return service

# show tech の自動取得  
def collect_showtech(service,device):
    command = "show tech"
    # 指定デバイスに対して show tech 実行(timeout=600秒)
    showtech = service.inventory[device.strip()].exec(command,timeout=600).wait().result.data
    # カレントディレクトリへ show tech ファイルを作成
    path = os.getcwd()
    now = datetime.datetime.now()
    file = path + "\\" + device + "_" + now.strftime('%Y%m%d_%H%M%S') + '.log'
    with open(file,mode='w') as f:
        f.write(showtech)
        print("Generated show tech file: %s" % file)

# IOSd/IOS-XE 各プロセスの CPU / メモリ使用率のモニタリング
def cpu_mem_monitor(service,device):
    # CPU / メモリ状態を取得するための各種コマンド
    iosd_cpu_command = "show processes cpu sorted 5sec"
    iosd_mem_command = "show processes memory sorted "
    iosxe_cpu_command = "show processes cpu platform sorted 5sec"
    iosxe_mem_command = "show processes memory platform sorted"

    i = 0
    j = 0
    z = 0

    iosd_cpu = []
    iosd_mem = []
    iosxe_cpu = []
    iosxe_mem = []
    temp_iosd_cpu = []
    temp_iosd_mem = []
    temp_iosxe_cpu = []
    temp_iosxe_mem = []
    disp_iosd_cpu = []
    disp_iosd_mem = []
    disp_iosxe_cpu = []
    disp_iosxe_mem = []

    # 10 回転したら終了する
    for i in range(10):
        j = 0
        for j in range(4):
            z = 0
            # 各コマンド結果取得 & リスト化
            iosd_cpu = service.inventory[device.strip()].exec(iosd_cpu_command,timeout=600).wait().result.data.split('\n')
            iosd_mem = service.inventory[device.strip()].exec(iosd_mem_command,timeout=600).wait().result.data.split('\n')
            iosxe_cpu = service.inventory[device.strip()].exec(iosxe_cpu_command,timeout=600).wait().result.data.split('\n')
            iosxe_mem = service.inventory[device.strip()].exec(iosxe_mem_command,timeout=600).wait().result.data.split('\n')

            # ヘッダ行 & Top 6 以降の要素の排除
            del iosd_cpu[0:3]
            del iosd_mem[0:6]
            del iosxe_cpu[0:6]
            del iosxe_mem[0:5]
            del iosd_cpu[5:]
            del iosd_mem[5:]
            del iosxe_cpu[5:]
            del iosxe_mem[5:]
            
            # 表示する情報を抽出して加工
            for z in range(5):
                temp_iosd_cpu = iosd_cpu[z].split()
                # IOSd の場合、プロセス名が空白で split される場合があるのでその対策
                if len(temp_iosd_cpu) > 9:
                    Y = 0
                    y = 0
                    Y = len(temp_iosd_cpu) - 9
                    for y in range(Y):
                        temp_iosd_cpu[8] = temp_iosd_cpu[8] + "-" + temp_iosd_cpu[8+y+1]
                    
                temp_iosd_mem = iosd_mem[z].split()
                # IOSd の場合、プロセス名が空白で split される場合があるのでその対策
                if len(temp_iosd_mem) > 8:
                    Y = 0
                    y = 0
                    Y = len(temp_iosd_mem) - 8
                    for y in range(Y):
                        temp_iosd_mem[7] = temp_iosd_mem[7] + "-" + temp_iosd_mem[7+y+1]

                temp_iosxe_cpu = iosxe_cpu[z].split()
                temp_iosxe_mem = iosxe_mem[z].split()

                disp_iosd_cpu.append(str(temp_iosd_cpu[8]) + " : " + str(temp_iosd_cpu[4]))
                disp_iosd_mem.append(str(temp_iosd_mem[7]) + " : " + str(round(int(temp_iosd_mem[4])/1000)) + "k")
                disp_iosxe_cpu.append(str(temp_iosxe_cpu[7]) + " : " + str(temp_iosxe_cpu[2]))
                disp_iosxe_mem.append(str(temp_iosxe_mem[6]) + " : " + str(round(int(temp_iosxe_mem[5])/1000)) + "k")

                temp_iosd_cpu.clear()
                temp_iosd_mem.clear()
                temp_iosxe_cpu.clear()
                temp_iosxe_mem.clear()
            
            # 表示処理
            # 実行時の表示イメージは下記の通り。情報の更新間隔はネットワークに依存。
            #
            # Usage Top 5 - Asof : [取得日時]
            # Device Name: [対象デバイス名]
            #
            # [IOSd - CPU]     
            # xxxxx : xx%
            # xxxxx : xx%
            # xxxxx : xx% 
            #
            # [IOSd - MEM]  
            # xxxxx : xxk
            # xxxxx : xxk
            # xxxxx : xxk
            #
            # [IOS-XE - CPU]
            # xxxxx : xx%
            # xxxxx : xx%
            # xxxxx : xx%
            #
            # [IOS-XE - MEM] 
            # xxxxx : xxk
            # xxxxx : xxk
            # xxxxx : xxk
            
            now = datetime.datetime.now().strftime('%m/%d_%H:%M:%S')
            os.system('cls')
            print(f'Usage Top 5 - Asof: {now}\nDevice Name: {device.strip()}\n\n[IOSd - CPU]\n\
{disp_iosd_cpu[0]}\n{disp_iosd_cpu[1]}\n{disp_iosd_cpu[2]}\n{disp_iosd_cpu[3]}\n{disp_iosd_cpu[4]}\n\n[IOSd - MEM]\n\
{disp_iosd_mem[0]}\n{disp_iosd_mem[1]}\n{disp_iosd_mem[2]}\n{disp_iosd_mem[3]}\n{disp_iosd_mem[4]}\n\n[IOS-XE - CPU]\n\
{disp_iosxe_cpu[0]}\n{disp_iosxe_cpu[1]}\n{disp_iosxe_cpu[2]}\n{disp_iosxe_cpu[3]}\n{disp_iosxe_cpu[4]}\n\n[IOS-XE - MEM]\n\
{disp_iosxe_mem[0]}\n{disp_iosxe_mem[1]}\n{disp_iosxe_mem[2]}\n{disp_iosxe_mem[3]}\n{disp_iosxe_mem[4]}\n',end='',flush=True)
            
            disp_iosd_cpu.clear()
            disp_iosd_mem.clear()
            disp_iosxe_cpu.clear()
            disp_iosxe_mem.clear()
            time.sleep(1)

# インターフェースのリアルタイムモニタリング 
def interface_monitor(service,device):
    # インターフェース状態を取得するためのコマンド
    command = "show interface"
    
    i = 0
    j = 0
    z = 0
    k = 0
    x = 0

    int_idx = []
    temp_list = []
    disp_int = ""
    disp_link = ""
    disp_desc = ""
    disp_ip = ""
    disp_dup = ""
    disp_speed = ""
    disp_input_rate = ""
    disp_input_pkt = ""
    disp_input_byte = ""
    disp_output_rate = ""
    disp_output_pkt = ""
    disp_output_byte = ""
    disp_crc = ""

    
    # 10 回転したら終了する
    for i in range(10):
        j = 0
        for j in range(4):
            z = 0
            k = 0
            x = 0
            # 結果取得 & リスト化
            interface = service.inventory[device.strip()].exec(command,timeout=600).wait().result.data.split('\n')
            now = datetime.datetime.now().strftime('%m/%d_%H:%M:%S')
            disp_str = "Interface Status - Asof: " + now + "\nDevice Name: " + device.strip() + "\n\n"
            
            del interface[0]
            
            # 文字列 GigabitEthernet が含まれるインデックスを保管
            int_idx = ([k for k, x in enumerate(interface) if 'GigabitEthernet' in x]) 
            
            # 表示する情報を抽出して加工
            for z in range(len(int_idx)):

                # インターフェース名/リンク状態を抽出
                temp_list = interface[int(int_idx[z])].split()
                disp_int = temp_list[0]
                disp_link = temp_list[2].replace(',','')
                temp_list.clear()
                
                # Description 抽出
                temp_list = interface[int(int_idx[z])+2].split()
                disp_desc = temp_list[1]
                temp_list.clear()
                
                # IP 抽出
                temp_list = interface[int(int_idx[z])+3].split()
                disp_ip = temp_list[3]
                temp_list.clear()
                
                # duplex 抽出
                temp_list = interface[int(int_idx[z])+8].split()
                disp_dup = temp_list[0]
                temp_list.clear()
                
                # speed 抽出
                temp_list = interface[int(int_idx[z])+8].split()
                disp_speed = temp_list[2].replace(',','')
                temp_list.clear()
                
                # input rate 抽出
                temp_list = interface[int(int_idx[z])+16].split()
                disp_input_rate = str(round(int(temp_list[4])/1000000)) + "Mbit/s"
                temp_list.clear()
                
                # input packets 抽出
                temp_list = interface[int(int_idx[z])+18].split()
                disp_input_pkt = temp_list[0]
                temp_list.clear()
                
                # input bytes 抽出
                temp_list = interface[int(int_idx[z])+18].split()
                disp_input_byte = str(round(int(temp_list[3])/1000000)) + "Mbytes"
                temp_list.clear()
                
                # output rate 抽出
                temp_list = interface[int(int_idx[z])+17].split()
                disp_output_rate = str(round(int(temp_list[4])/1000000)) + "Mbit/s"
                temp_list.clear()
                
                # output packets 抽出
                temp_list = interface[int(int_idx[z])+23].split()
                disp_output_pkt = temp_list[0]
                temp_list.clear()
                
                # output bytes 抽出
                temp_list = interface[int(int_idx[z])+23].split()
                disp_output_byte = str(round(int(temp_list[3])/1000000)) + "Mbytes"
                temp_list.clear()
                
                # crc 抽出
                temp_list = interface[int(int_idx[z])+21].split()
                disp_crc = temp_list[3]
                temp_list.clear()
                
                
                # 表示処理
                # 実行時の表示イメージは下記の通り。情報の更新間隔はネットワークに依存。
                #
                # Interface Status - Asof : [取得日時]
                # Device Name: [対象デバイス名]
                #
                # [インターフェース名]     
                # link : xx
                # description : xxxx
                # ip address : xxxx
                # duplex : xxxx
                # link speed : xxxx
                # 5 min input rate : xxxxx 
                # 5 min input packets : xxxxx 
                # 5 min input bytes : xxxxx 
                # 5 min output rate : xxxxx 
                # 5 min output packets : xxxxx 
                # 5 min output bytes : xxxxx 
                # crc error count : xxxxx
                
                # 出力文字成形
                disp_str = disp_str + "[" + disp_int + "]\n" + "link : " + disp_link + "\n" + "description : " +\
                disp_desc + "\n" + "ip address : " + disp_ip + "\n" + "duplex : " + disp_dup + "\n" + "link speed : " +\
                disp_speed + "\n" + "5 min input rate : " + disp_input_rate + "\n" + "5 min input packets : " +\
                disp_input_pkt + "\n" + "5 min input bytes : " + disp_input_byte + "\n" + "5 min output rate : " +\
                disp_output_rate + "\n" + "5 min output packets : " + disp_output_pkt + "\n" + "5 min output bytes : " +\
                disp_output_byte + "\n" + "crc error count : " + disp_crc + "\n\n"

            os.system('cls')
            print(disp_str,end='',flush=True)
            time.sleep(5)

# メイン画面
def main():
    # 変数部 
    global email
    global serviceid

    try:
        # email と service ID の入力 
        email = input("enter your email address:")
        serviceid = input("enter service id:")    
    
        # コンソールのフラッシュ
        os.system('cls')
        # メニュー表示
        menu = questionary.select(
            'Please choice the instruction you want',
            choices=["1.Collect show tech","2.CPU/Memory Monitor","3.Interface Monitor","4.Exit"]
        ).ask()

        # show tech の自動取得処理呼び出し  
        if menu == "1.Collect show tech":
            # service 接続
            with Client.create() as client:
                service=service_attach(client)
            # 対象 device 入力
                device = input("enter device name you want to access:")            
            # show tech 取得処理呼び出し
                collect_showtech(service,device)
                sys.exit()
                
        # CPU / メモリ使用率のリアルタイムモニタリング処理呼び出し
        elif menu == "2.CPU/Memory Monitor":
            # service 接続
            with Client.create() as client:
                service=service_attach(client)
            # 対象 device 入力
                device = input("enter device name you want to access:")            
            # モニタリング 処理呼び出し
                cpu_mem_monitor(service,device)
                sys.exit()

        # インターフェースのリアルタイムモニタリング処理呼び出し 
        elif menu == "3.Interface Monitor":
            # service 接続
            with Client.create() as client:
                service=service_attach(client)
            # 対象 device 入力
                device = input("enter device name you want to access:")   
            # モニタリング処理呼び出し
                interface_monitor(service,device)
                sys.exit()

        # スクリプト終了
        elif menu == "4.Exit":
            print("Bye!")
            sys.exit()

    except Exception as e:
        print("Fatal: %s" % e)

# init
if __name__ == "__main__":
    main()
```

</details>

::: note info
上記スクリプトでは、別途 questionary 等の機能も pip でインストールしています。 
:::

### 6. スクリプトの実行

完成したスクリプトは「automation.py」という名称で保存し、実行します。

![automation-init-dir.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/19532b4e-1371-25fb-663c-e3d17d9afd43.jpeg)

実行するとメールアドレスと Service ID の入力が求められるので、事前に入力します。  

![automation-login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/9fac639c-07ac-8a94-3eca-2a35bcaba6d1.jpeg)


**1) show tech の自動取得**

まず show tech の自動取得を実行してみます。
メニューから Collect show tech を選択すると、Inventory に登録されている機器が一覧表示されます。対象デバイスとして「 c8kv-1 」を入力すると、約 1 分後に show tech ファイルを作成した旨のメッセージが出力されます。  

![automation-collect-show-tech1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/40b0634a-d2dd-8f69-d91c-d2ac0df4bedf.jpeg)

![automation-collect-show-tech2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/ff6221ed-d816-a4dd-dc0f-89e2eaca93e8.jpeg)

カレントディレクトリを再度確認すると、ログファイルが生成されていることが分かります。ログファイルの中身を見ると、show tech の実行結果が記録されています。無事に show tech 結果が自動取得されました。  

![automation-collect-show-tech3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/bc8fe7a6-c3ae-d6e0-f1bb-ee394ea85661.jpeg)

![automation-collect-show-tech4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/bb1db214-641c-4256-f984-ecbf60bd6852.jpeg)


**2) IOSd/IOS-XE 各プロセスの CPU / メモリ使用率のリアルタイムモニタリング**

次に IOSd/IOS-XE 各プロセスの CPU / メモリ使用率のリアルタイムモニタリングを実行してみます。メニューから CPU/Memory Monitor を選択し、対象デバイスとして「 c8kv-1 」を入力すると、約 15 秒間隔で IOSd/IOS-XE 各プロセスの CPU / メモリ使用率の Top 5 がリアルタイムに表示されました。なお、情報の更新間隔はお使いのネットワーク速度や指定デバイスの応答速度によって変動します。  

:::note info
途中で処理を停止させたい場合は、Ctrl + C にて強制終了させてください。
:::

![automation-cpumem1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/908e6397-2b3d-fbba-89ad-59cf08fc2db2.jpeg)

![automation-cpumem2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/d33519f3-58fb-a5d4-2067-1cc61faed483.jpeg)


**3) インターフェースのリアルタイムモニタリング**

最後にインターフェースのリアルタイムモニタリングを実行してみます。  
メニューから Interface Monitor を選択し、対象デバイスとして「 c8kv-1 」を入力すると、約 10 秒間隔でインターフェースの統計情報がリアルタイムに表示されました。なお、情報の更新間隔はお使いのネットワーク速度や指定デバイスの応答速度によって変動します。(link ステータスの後ろのカンマを replace で消すの忘れてた・・スクリプト上には修正反映済なのでご安心を)  

:::note info
途中で処理を停止させたい場合は、Ctrl + C にて強制終了させてください。
:::

![automation-interface1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/0f9147c2-c308-5570-d1b3-254f9874bb1c.jpeg)

![automation-interface2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/23d82956-c1b4-72a4-167f-8eee317cf057.jpeg)

上記の結果だけですと少し分かりにくいので、Client1 から iperf を使って Client2 に対するトラフィックを印加してみます。  

![automation-interface3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/210af751-0c06-6f40-e396-146aa0272a5f.jpeg)

本スクリプトの Interface Monitor は、定期的に show interface コマンドを発行し、その実行結果から必要情報を抽出・加工して表示させます。そのため、トラフィックレートなどは 5 分平均のものとなりますが、トラフィック印加後にしばらくモニタすると、トラフィックレートやパケット数などの向上が見られ、正しくモニタリングできていることが分かります。  

![automation-interface4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/1cf83264-3366-3673-d530-9a5eb76ac29f.jpeg)

![automation-interface5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817499/a710f12c-17a8-a36b-f2f0-f3223c211ea8.jpeg)

## まとめ

今回はサンプル程度となりますが、RADKit と Python を併用することで遠隔からネットワーク機器の操作を自動化することの片鱗が見られたかと思います。  

RADKit は無料で利用できますので、Python によるスクリプト開発が得意な方であれば、***ネットワーク機器の遠隔運用などのサービスを開発することもできる*** のではないでしょうか。  

優雅にお酒を飲みながら自動化スクリプトを使ってサクッとトラブルシュートする、というのも夢の話ではないかもしれません！！(これが言いたくてネットワーク構成図にお酒の絵を描いてたのね・・)  

<br>

遊びの延長だと思って、是非 RADKit を活用してみてください。