Cisco Catalyst IOS-XEでのPythonやBash

# これは何？
Catalyst 3850や3650といった普及版（企業向け）L3スイッチのIOS-XE16.5.1aにて、ゲストシェル（Bash）やPythonスクリプティングがサポートされたらしいので、取り急ぎどんなモノか確認するメモ。

[Cisco IOS XE Everest 16.5.1aのリリースノート](http://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst3850/software/release/16-5/release_notes/ol-16-5-3850.html#pgfId-1342703)

該当部分は以下。スイッチ上でLXC（Linux Container）が動くらしい。
> Guest Shell—A secure LXC container that is an embedded Linux environment and enables you to develop and run Linux and custom Python applications for automated control and management of Cisco switches. Guest Shell is bundled with the software image (cat3k_caa-guestshell.<release name>.SPA.pkg)and can be installed using the guestshell enable command.

従来のIOSでも、Tclスクリプティングが昔からサポートされているが、Pythonスクリプティングができるとうれしい人が多いかもしれない。[EEM](http://qiita.com/kikuta1978/items/5d7d92e7f35d0a03922b)のアクションからも起動できるとのこと。

> Python Scripting—Supports Python v2.7 in both interactive and non-interactive (script) modes and is available in the Guest Shell.
The Python scripting capability gives programmatic access to YANG data models and the device's command-line interface (CLI) to perform various tasks such as Zero Touch Provisioning (ZTP) and Embedded Event Manager (EEM) actions.


## 背景
各社データセンタースイッチや通信事業者向けのスイッチ、ルータでは普通にサポートされていますが、企業LAN向けのスイッチ、ルータでもこのあたりがサポートされてくると、一気に自動化やプログラマビリティも身近になるのではないでしょうか。

一般的にNMSやツール類（Ansibleなど）での外部からの装置アクセスをOff-boxプログラミングとよぶのに対し、ルータやスイッチ装置内部に配置したコードを使った自動化をOn-boxプログラミングとよびます。これらは相互補完であり、ネットワークリーチャビリティがなくなった装置内部でのログ取得を証跡用途に残したり、装置内部のロジックで経路を切り替えたりといった用途など、On-boxも多く使われています。

On-boxプログラミングは標準手法というよりも装置やメーカー依存になりやすく、オープンコミュニティでは（オープンなツールに比べて）議論されにくいトピックでもあります。また、トラブル時のワークアラウンドにも多用されるため、事例にもなりにくい（公開されない）ネタです。（こっそり使っている）

# 確認環境
## IOS-XEバージョン

```
Cat3850-3#sho ver | i .bin
System image file is "flash:cat3k_caa-universalk9.16.05.01a.SPA.bin"
```

## 設定
```cisco
Cat3850-3#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
Cat3850-3(config)#iox
Cat3850-3(config)#exit
Cat3850-3#
Cat3850-3#guestshell enable 
Management Interface will be selected if configured
Please wait for completion
guestshell is in RUNNING state

Cat3850-3#
```

## 確認
```
Cat3850-3#show iox           

IOx Infrastructure Summary:
---------------------------
IOx service (CAF)    : Running 
IOx service (HA)     : Running 
IOx service (IOxman) : Running 
Libvirtd             : Running 
```

```
Cat3850-3#show app-hosting detail 
State                  : RUNNING
Author                 : Cisco Systems
Application
  Type                 : lxc
  App id               : guestshell
  Name                 : guestshell
  Version              : 0.1
Activated profile name : custom
  Description          : MontaVista guestshell
Resource reservation
  Memory               : 256 MB
  Disk                 : 1 MB
  CPU                  : 800 units
  VCPU                 : 1
Attached devices
  Type              Name        Alias
  ---------------------------------------------
  Serial/shell
  Serial/aux
  Serial/Syslog                 serial2
  Serial/Trace                  serial3

Network interfaces
   ---------------------------------------
```

# 動作確認

## Pythonインタラクティブモード
```
Cat3850-3#guestshell run python
Python 2.7.11 (default, Feb  3 2017, 19:43:44) 
[GCC 4.7.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "Hello!"
>>> print a
Hello!
>>> import cli
>>> cli.clip('show ip int brie | i Vlan1')

Vlan1                  10.71.154.98    YES NVRAM  up                    up  
>>> 
>>> output=cli.clip('show clock')

*09:47:26.825 UTC Tue Jun 6 2017

>>> print (output)
None
>>> output=cli.cli('show clock')
>>> print (output)

*09:48:21.961 UTC Tue Jun 6 2017

>>> 
>>> cli.configure(["interface GigabitEthernet1/0/7", "no shut", "end"])
[ConfigResult(success=True, command='interface GigabitEthernet1/0/7', line=1, output='', notes=None), ConfigResult(success=True, command='no shut', line=2, output='', notes=None), ConfigResult(success=True, command='end', line=3, output='', notes=None)]
```

##ゲストシェル
```bash
Cat3850-3#guestshell 
[guestshell@guestshell ~]$ uname -a
Linux guestshell 3.10.101.cge-rt110 #1 SMP Sat Mar 11 19:54:31 PST 2017 mips64 GNU/Linux
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ cat /proc/version 
Linux version 3.10.101.cge-rt110 (nosbuild@nosdistros-bld4) (gcc version 4.7.0 (GCC) ) #1 SMP Sat Mar 11 19:54:31 PST 2017
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ cd /
[guestshell@guestshell /]$ ls
bin          data         flash        local        proc         tmp
boot         dev          home         lost+found   sbin         usr
bootflash    etc          lib          media        selinux      var
cisco        fix_sshd.sh  lib64        mnt          sys
[guestshell@guestshell /]$ cd ~
[guestshell@guestshell ~]$
```
Catalyst3850/3650は、MIPS CPUなので、制限はありそうです。

※参考までに、Catalyst9300でも同様の確認をしてみたので追記します。

```bash
C9300-24U#guestshell 
[guestshell@guestshell ~]$ uname -a
Linux guestshell 4.4.51 #1 SMP Sun Jun 4 17:58:12 PDT 2017 x86_64 x86_64 x86_64 GNU/Linux
[guestshell@guestshell ~]$ 
[guestshell@guestshell ~]$ cat /proc/version 
Linux version 4.4.51 (xelinux@xe-linux-bld2) (gcc version 5.3.0 (GCC) ) #1 SMP Sun Jun 4 17:58:12 PDT 2017
[guestshell@guestshell ~]$ 
[guestshell@guestshell ~]$ cd /
[guestshell@guestshell /]$ ls
bin        cisco                        dev          flash  lib64       media  proc      run      srv  unfix_sshd.sh
boot       created.2016-05-31.14:23:44  etc          home   local       mnt    root      sbin     sys  usr
bootflash  data                         fix_sshd.sh  lib    lost+found  opt    rr_moved  selinux  tmp  var
[guestshell@guestshell /]$ 
```

以下、Catalyst3850の動作ログに戻ります。

```bash
[guestshell@guestshell ~]$ pwd
/home/guestshell
[guestshell@guestshell ~]$ pip list
pip (8.1.2)
setuptools (22.0.5)
[guestshell@guestshell ~]$ 
[guestshell@guestshell ~]$ ls
[guestshell@guestshell ~]$ 
[guestshell@guestshell ~]$ cd /flash/
[guestshell@guestshell flash]$ ls | grep .bin
cat3k_caa-universalk9.16.05.01a.SPA.bin
[guestshell@guestshell flash]$ 
[guestshell@guestshell flash]$ touch test.txt
[guestshell@guestshell flash]$ ls | grep test 
test.txt
[guestshell@guestshell flash]$
[guestshell@guestshell flash]$
[guestshell@guestshell flash]$ vi sho-ver.py
[guestshell@guestshell flash]$ cat sho-ver.py 
#!/usr/bin/python

import cli
print cli.execute('show version')
[guestshell@guestshell flash]$
[guestshell@guestshell flash]$ python ./sho-ver.py | grep bin
System image file is "flash:cat3k_caa-universalk9.16.05.01a.SPA.bin"
[guestshell@guestshell flash]$ 
```
普通に使えそうです。
とりあえず/flashに、flash:がマウントされているのと、viが使えるのでファイル編集とかも楽そうです。

## EEMから実行
```
Cat3850-3#sho flash: | i py
  9         64 Jun 06 2017 09:59:24.0000000000 +00:00 sho-ver.py
Cat3850-3#
Cat3850-3#sh run | sec event manager
event manager applet TEST
 event none
 action 100 cli command "enable"
 action 200 cli command "guestshell run python /bootflash/sho-ver.py"
Cat3850-3#
Cat3850-3#debug event manager action cli 
Debug EEM action cli debugging is on
Cat3850-3#
Cat3850-3#
Cat3850-3#event manager run TEST         

*Jun  6 10:08:14.106: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : CTL : cli_open called.
*Jun  6 10:08:14.108: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cat3850-3>
*Jun  6 10:08:14.108: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : IN  : Cat3850-3>enable
*Jun  6 10:08:14.220: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cat3850-3#
*Jun  6 10:08:14.220: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : IN  : Cat3850-3#guestshell run python /bootflash/sho-ver.py
Cat3850-3#
*Jun  6 10:08:18.549: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cisco IOS XE Software, Version 16.05.01a
*Jun  6 10:08:18.550: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cisco IOS Software [Everest], Catalyst L3 Switch Software (CAT3K_CAA-UNIVERSALK9-M), Version 16.5.1a, RELEASE SOFTWARE (fc2)
*Jun  6 10:08:18.550: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Technical Support: http://www.cisco.com/techsupport
*Jun  6 10:08:18.550: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Copyright (c) 1986-2017 by Cisco Systems, Inc.
*Jun  6 10:08:18.550: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Compiled Tue 30-May-17 00:59 by mcpre
*Jun  6 10:08:18.550: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cisco IOS-XE software, Copyright (c) 2005-2017 by cisco Systems, Inc.
*Jun  6 10:08:18.551: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : All rights reserved.  Certain components of Cisco IOS-XE software are
*Jun  6 10:08:18.551: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : licensed under the GNU General Public License ("GPL") Version 2.0.  The
*Jun  6 10:08:18.551: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : software code licensed under GPL Version 2.0 is free software that comes
*Jun  6 10:08:18.551: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such
*Jun  6 10:08:18.551: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : GPL code under the terms of GPL Version 2.0.  For more details, see the
*Jun  6 10:08:18.552: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : documentation or "License Notice" file accompanying the IOS-XE software,
*Jun  6 10:08:18.552: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : or the applicable URL provided on the flyer accompanying the IOS-XE
*Jun  6 10:08:18.552: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : software.
*Jun  6 10:08:18.552: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : ROM: IOS-XE ROMMON
*Jun  6 10:08:18.552: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : BOOTLDR: CAT3K_CAA Boot Loader (CAT3K_CAA-HBOOT-M) Version 3.58, RELEASE SOFTWARE (P)
*Jun  6 10:08:18.553: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Cat3850-3 uptime is 1 day, 15 hours, 57 minutes
*Jun  6 10:08:18.553: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : Uptime for this control processor is 1 day, 16 hours, 0 minutes
*Jun  6 10:08:18.553: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : System returned to ROM by reload
*Jun  6 10:08:18.553: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : OUT : System image file is "flash:cat3k_caa-universalk9.16.05.01a.SPA.bin"
*Jun  6 10:08:18.553: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : CTL : 20+ lines read from cli, debug output truncated
*Jun  6 10:08:18.554: %HA_EM-6-LOG: TEST : DEBUG(cli_lib) : : CTL : cli_close called.
*Jun  6 10:08:18.556: 
*Jun  6 10:08:18.556: tty is now going through its death sequence
Cat3850-3#
```
Nexusっぽいですが、IOSだけにスクリプトを起動するEventが多くサポートされていることもあり、色々と面白い使い方ができそうです。

※本バージョンで確認できるEEMイベントの一覧。
timerやsyslog、interfaceは使いやすいです。
その他、routing tableやmac address table、NetFlow Cacheをトラックしてイベント発行したり、CDPやLLDPを元にするなど（neighbor-discovery）、凝ったロジックが実装でき、個人的に好きな機能です。これまではAction用にTclスクリプトを書いていましたが、これからはPythonスクリプトも動くということで、より利用者が増えるかもしれません。（一回使うと、便利でパワフルなのでリピーターになってしまう）

```
Cat3850-3(config)#event mana app TEST
Cat3850-3(config-applet)#event ?
  application         Application specific event
  cli                 CLI event
  config              Configuration policy event
  counter             Counter event
  env                 Environmental event
  gold                GOLD event
  identity            Identity event
  interface           Interface event
  ioswdsysmon         IOS WDSysMon event
  ipsla               IPSLA Event
  mat                 MAC address table event
  neighbor-discovery  Neighbor Discovery event
  nf                  NF Event
  none                Manually run policy event
  oir                 OIR event
  rf                  Redundancy Facility event
  routing             Routing event
  snmp                SNMP event
  snmp-notification   SNMP Notification Event
  snmp-object         SNMP object event
  syslog              Syslog event
  tag                 event tag identifier
  timer               Timer event
```

# 参考
公式マニュアルには、まだほとんど情報がありませんが、Cisco DevNetやコミュニティフォーラムには情報が出始めています。本格的にはこれから、という感じのようです。

- https://developer.cisco.com/site/python/docs/#on-box-python-and-guestshell/ios-xe-16.5

- https://developer.cisco.com/media/iox-dev-guide-11-28-16/platforms/platform-isr4k/

- https://communities.cisco.com/community/developer/blog/2017/04/17/introducing-python-and-guest-shell-on-ios-xe-165