NetDevOps!? GitLab から LANスイッチ On-box CentOS 操作

# はじめに
この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2020 （二枚目） の 4日目として投稿しています。

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2

今年は初の二枚目もあって、びっくり！有志すごい！

# これはなに？

- Catalystの[Guestshell](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/173/b_173_programmability_cg/guest_shell.html)/[AppHosting](https://developer.cisco.com/app-hosting/)で、[Front-Panel Network Port Access](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/173/b_173_programmability_cg/application_hosting.html#id_94841)のサンプルコンフィグ
- GitLab CI/CD ジョブとして、Catalyst On-box Shell/Python の起動と確認
- タイトルはネタっぽくしてますが、内容はわりと地味です

![Screen Shot 2020-12-03 at 13.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/5d4f45f7-2e98-476a-7741-0ff9881e80d7.png)




# 背景
最近のIOS XEでは、CentOSやDockerをネットワーク機器上で動かすAppHosting機能がサポートされています。特に、On-boxなbashは汎用性がありそれなりに使われるようになりました。特に決まったユースケースというよりは日常タスクやスクリプトなど個人的にも有用だと感じます。

IOS Guestshellを使うための設定は、機能が登場して以来、何度か設定の仕方が変わっています。よくある設定例では、外部ネットワークと内部アプリケーションをNATで接続する例かと思います。[去年のカレンダーの記事：IOS-XEのOn-box Pythonで行う機器監視](https://qiita.com/ecodrive/items/2c244fd6b3d6dd1df95f)も参考になります。私が書いた[三年前の記事：Cisco Catalyst IOS-XEでのPythonやBash](https://qiita.com/ecodrive/items/2c244fd6b3d6dd1df95f)では、特にインターフェースを指定せずにいきなり起動させていましたが、このときはポート固定でマネジメントインターフェースが接続される仕様になっていました（今は変わっています）。

Guestshellのよくあるデモとしては、主にIOS XEが何か内部イベント（タイマーやSyslogなどでしょうか、EEMを組み合わせることが多いですね）をトリガーに、装置内部で何かタスクを実行し、外部アプリケーションへ通知する、といった例が多いです。EEMでの内部イベントの捕捉というところが特徴的で、外部からはわからない非同期なトリガーが可能だからです。一方、別のアプリケーションからのWebhookなどでAPIアクセスを受けとったりとなると、NATではちょっと面倒臭かったです。

ということで時間が経ち、IOS XE 16.12.1から、CatalystではフロントポートのVlanを内部のホスティングアプリに接続できるようになりました。リリースノートはこちら[Software Features in Cisco IOS XE Gibraltar 16.12.1 - Guest Shell and App Hosting: Front-Panel Network Port Access](https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9300/software/release/16-12/release_notes/ol-16-12-9300.html#concept_oxb_rjj_d3b)です。何かと便利な設定なので、すぐにサンプルコンフィグをコピペできるように記事にしておきたいなと思ったのが元々の動機です。

# Catalystの設定 - AppHosting Front-Panel Network Port Access

動作確認バージョンは以下。

```
Cat9300TMT02#sh ver | i IOSXE
Cisco IOS Software [Amsterdam], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 17.3.2a, RELEASE SOFTWARE (fc5)
*    1 41    C9300-24P          17.03.02a         CAT9K_IOSXE           INSTALL
```

フロントパネル、つまり前面のポートのVlanを内部インターフェースであるAppGigabitEthernetにくっつける準備です。

```
interface GigabitEthernet1/0/24
 switchport access vlan 10
!
interface Vlan10
 ip address 10.71.154.50 255.255.255.248
!
interface AppGigabitEthernet1/0/1
 switchport trunk allowed vlan 10
 switchport mode trunk
```

IOS XE 17.3.1から、Guestshell周りが更新されており、CentOSやPythonのデフォルトバージョンがあがっています（ここ重要）。IOS XEをバージョンアップした場合でも、前から作っていた場合は古いGuestshellが保持されているので、新規から作り直したい場合は一旦Destroyしてから作り直すのがお勧めです。

```
Cat9300TMT02#guestshell destroy 
Guestshell destroyed successfully 

Cat9300TMT02#
Cat9300TMT02#guestshell enable 
Interface will be selected if configured in app-hosting
Please wait for completion

Guestshell enabled successfully
```

CentOS8, Python3が確認できます。

```
[guestshell@guestshell ~]$ cat /etc/redhat-release 
CentOS Linux release 8.1.1911 (Core) 
[guestshell@guestshell ~]$ 
[guestshell@guestshell ~]$ python3 -V
Python 3.6.8
[guestshell@guestshell ~]$ 
```

Vlan10に割り当てた/29マスクのセグメントから、GuestshellにもIPアドレスを設定します。

```
app-hosting appid guestshell
 app-vnic AppGigabitEthernet trunk
  vlan 10 guest-interface 0
   guest-ipaddress 10.71.154.51 netmask 255.255.255.248
 app-default-gateway 10.71.154.50 guest-interface 0
 app-resource profile custom
  persist-disk 200
  name-server0 64.104.14.184
 start
```

この状態で、ioxとguestshell enableをすると、以下のように立ち上がります。このCentOSは、Vlan10のIPアドレスでネットワーク上からアクセスできるようになりました。汎用性が高まりました。

```
Cat9300TMT02#show app-hosting detail appid guestshell
App id                 : guestshell
Owner                  : iox
State                  : RUNNING
Application
  Type                 : lxc
  Name                 : GuestShell
  Version              : 3.1.0
  Description          : Cisco Systems Guest Shell XE for x86_64
  Path                 : /guestshell/:guestshell.tar
  URL Path             : 
Activated profile name : custom

Resource reservation
  Memory               : 256 MB
  Disk                 : 200 MB
  CPU                  : 800 units
  VCPU                 : 1

Attached devices
  Type              Name               Alias
  ---------------------------------------------
  serial/shell     iox_console_shell   serial0
  serial/aux       iox_console_aux     serial1
  serial/syslog    iox_syslog          serial2
  serial/trace     iox_trace           serial3

Network interfaces
   ---------------------------------------
eth0:
   MAC address         : 52:54:dd:78:22:d7
   IPv4 address        : 10.71.154.51
   Network name        : mgmt-bridge-v10

Port forwarding
  Table-entry  Service  Source-port  Destination-port
  ---------------------------------------------------
```
 
# GitLab Runnerを使ってOn-box CIっぽくしてみる

それでは、On-boxなCentOSにGitLab Runnerをインストールして、外部のGitLabからトリガーしてIOS XE内部から操作してみます。GitLab自体は、Catalystからアクセスできるネットワーク上に設置済みという前提です。

## GitLabおよびGitLab Runner

CatalystのCentOSからGitLabにSSHできるようにしておきます。その他、gitやpythonモジュールなど、適当にインストールしてください。

```bash:CentOS-on-Catalyst

ssh-keygen -t rsa -b 4096
cat ~/.ssh/id_rsa.pub
<snip>
```
sshの公開鍵をgitlabに登録しておきます。
![Screen Shot 2020-12-02 at 15.37.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/06919548-b496-b25e-3c89-297f9745551f.png)


## GitLab RunnerをCatalyst上のCentOSにインストール, 設定

[公式ドキュメント](https://docs.gitlab.com/runner/install/linux-repository.html)に沿って、Catalyst上のCentOSにGitLab Runnerをインストールして設定します。以下のコマンドでインストール。

```bash:CentOS-on-Catalyst

sudo curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash
sudo yum install gitlab-runner
```

GitLabのアクセス情報とトークンを登録します。GitLabのSettings > CI/CDのところから、Runnerと結びつけるためのURLとTokenをコピーし、CentOSに設定します。

![Screen Shot 2020-12-02 at 17.21.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/d4bb9dd7-9875-5bfa-90d2-7cb2a4622be2.png)

以下のコマンドで設定します。

```bash:CentOS-on-Catalyst

gitlab-runner register
Enter the GitLab instance URL (for example, https://gitlab.com/): ## GitLabのURLを入力 ##
Enter the registration token: ## Tokenを入力 ##
Enter a description for the runner:
[guestshell]: 
Enter tags for the runner (comma-separated):
```

これで、GitLab上でCatalyst 9300上のRunnerが確認できるようになります。

![Screen Shot 2020-12-02 at 12.02.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/c3ec400a-b58b-229c-ac84-509bf704f4e1.png)

## On-box python上で動作する適当なスクリプトを用意

それでは、GitLabのリポジトリを用意し、自分で設置した .gitlab-ci.yml にタスクを記述していきます。ここに置いたファイルが、パイプライン/Runner経由でOn-boxなCentOSに自動で送られます。そして、.gitlab-ci.ymlに基づいて、Catalyst上で実行されます。

今回は動作確認用として、printxmas2020.py がCatalyst上で起動することと、IOS XEと情報をやりとりできるように Catalystのフラッシュに保存したファイルの中身を GitLabのCI/CDのジョブの結果として、ブラウザ上で目視できることを確認してみます。


![Screen Shot 2020-12-02 at 12.10.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/7a9d47ad-9b3d-1d95-6c08-299b00d2e3f8.png)

## IOS XE と Guestshell の共有ディレクトリ
IOS XEのguestshellでは、デフォルトで flash:/guest-share というディレクトリが自動で出来ており、こちらに保存したファイルは、On-box CentOSからは /bootflash/guest-share/ から参照できるようになっています。

IOS XEから見た場合。EEM等を使って、適当な情報がここに自動保存/更新されるようにしておくとか、いかがでしょうね。この例では、ルーティングテーブルとRunning Configを保存しています。

```
Cat9300TMT02#dir flash:/guest-share
Directory of flash:/guest-share/

65754   -rw-             2751   Dec 2 2020 16:54:56 +09:00  routingtable.log
65753   -rw-            29192   Dec 2 2020 16:47:43 +09:00  running.cfg
```

Guestshellから見た場合。

```
[guestshell@guestshell ~]$ ls /bootflash/guest-share/ -l 
total 44
-rw-rw-r--. 1 nobody network-admin  2751 Dec  2 07:54 routingtable.log
-rw-rw-r--. 1 nobody network-admin 29192 Dec  2 07:47 running.cfg
```

## GitLab CIの設定と動作確認

GitLabのリポジトリ上に .gitlab-ci.yml を用意し、ここにCI/CDパイプライン経由でCatalystで実行したいジョブを記述します。簡単なPythonスクリプトをCatalystに送信して実行し、ついでにIOS XE CLIで保存してある情報をShellコマンドで表示してみます。これらのファイルは、ブラウザからファイルを作成して作ってもいいですし、もちろんGitで管理してもいいです。


```yaml:.gitlab-ci.yml

stages:
  - runner-test

cat_job:
  stage: runner-test
  script:
    - python3 printxmas2020.py
    - cat /bootflash/guest-share/routingtable.log
    - cat /bootflash/guest-share/running.cfg
  tags:
    - shell
  only:
    - master
```

printxmas2020.pyは、[去年書いた記事](https://qiita.com/kikuta2055/items/2c20f5bc2f86bef971b7)の流用です。

```python:printxmas2020.py

import sys

from termcolor import cprint
from pyfiglet import figlet_format

cprint(figlet_format('Merry Christmas 2020!'), 'white', 'on_magenta')
cprint(figlet_format('#DevNet'), 'white', 'on_blue')
```

GitLab上のファイルが更新されると、パイプラインからジョブが起動され、無事にジョブが成功したことが確認できました。


![Screen Shot 2020-12-02 at 17.42.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/dc4ca033-49b0-8be1-5737-ba413c5da24c.png)

GitLab CI/CDの画面から、Catalystに保存してあるルーティングテーブルや、コンフィグを確認してみました。On-boxなCentOSの操作をGitLab CIから起動、動作を確認してみました。

![Screen Shot 2020-12-02 at 17.43.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/522c2909-0845-d718-969e-2ab86067330c.png)

![Screen Shot 2020-12-02 at 17.45.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/da23c5b2-33c4-50e0-ab7c-4fbb6e071190.png)

.gitlab-cl.ymlの中でpwdさせるとわかりますが、実態はこんな感じで Catalystに同期され、実行されていることがわかります。

```
[root@guestshell guestshell]# cd  /home/gitlab-runner/builds/2XRWzh-s/0/kikuta/cicd
[root@guestshell cicd]# ls
README.md  printxmas2020.py  test.py
[root@guestshell cicd]#
```

# AppHostingに興味がある方
DevNetのサイトに、Dockerイメージの作り方とロードの方法が書いてあります。
https://developer.cisco.com/docs/app-hosting/

最近何かと話題のThousandEyesのエージェントも、AppHostingを利用して、Catalystやルーターに載せられます（でかいけど）。Webアクセスみたいなテストはいいですが、エージェント対向なUDPテスト（Media系など）の場合は、NATだと不便で、Front-Panel Network Port Accessが役立ちます。
https://docs.thousandeyes.com/product-documentation/enterprise-agents/enterprise-agent-installation-for-cisco-catalyst-9000-series-switches

# まとめ
だんだんと脱線して、一体全体誰得！？って感じになってしまいましたが、自分で個別にLinuxとかを用意できない環境において、On-boxなCentOSが自由に使えると、何かと可能性が拡がりそうなことがわかりました（だいぶ変な使い方をしているかもしれませんが...）。セキュリティ上の考慮はもちろん厳重に必要ですが、小さいエージェント（今回はRunner）をホストする一つの例の実験をしてみました。

ネットワーク装置に組み込まれた On-box Shellを使えば、通常外部からは取得しにくい情報が取れたりします（EEM Python Module や CLI Python Moduleがサポートされています）し、今回のように集中管理ツールのためのエージェントを載せられるのは、他にも実用性がありそうです。もちろん、On-boxなpyATSとかncclient、AnsibleやNSOでもいいですが、この辺の集中と分散のバランスを考えつつ、面白いソリューションを考えていきたいですね。個人的には、もうちょっとGitLabとCatalystやルーターを絡めて遊んでみたくなりました。今回は Catalyst/Runner が一つでやってますが、複数の Catalyst/Runner が一斉に動いたら、もっと面白そうです。

ちなみに、動作確認する中でわりとバグにもあたりました。具体的には、app-hostingのdnsの設定をコンフィグで書けるのですが、IOS XE 16.12だとそれを書くとapphosting的にGuestshellが起動しなくなる（なので、guestshell内の/etc/resolv.confに書く）とか、IOS XE 16.12だとCentOS7なんですがGitをバージョンを更新するのに苦労して結局いまいち動作がスッキリしないとか..。もし再現を試みられる方いらっしゃれば、IOS XE 17.3.1以降をお勧めします。

最後まで読んで頂きまして、ありがとうございました！

# 参考
[Programmability Configuration Guide, Cisco IOS XE Amsterdam 17.3.x](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/173/b_173_programmability_cg.html)
[GitLab](https://about.gitlab.com/)

# 免責事項

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