CatalystスイッチのコンテナからCisco Sparkに装置イベントを共有

# はじめに

前回の続きです。

参考：
シスコの普及型スイッチCatalystやルータの新しいOS（IOS-XE）で動くコンテナ上で、PythonやBashがサポートされた
[Cisco Catalyst IOS-XEでのPythonやBash](http://qiita.com/kikuta1978/items/1739d7d7063a20b1736f)

スイッチ上のPythonスクリプトは、IOSが内部で検出するイベントを元に任意のタイミングで自動で発行できることもわかった（EEM：Embedded Event Managerを使った発行）。さらに、EEMはPythonスクリプトで記述できることもわかった。後者の二つは似ているが、厳密には異なる。今回は、前者の動作ログ。今回も、Catalyst3850を利用。

（本当はCatalyst9300でやりたい。3850はMIPS CPU、9300はx86など、何かと制約が少ないと思われるため。）


参考：
[Cisco IOS EEMを使ったTclスクリプトの実行
](http://qiita.com/kikuta1978/items/5d7d92e7f35d0a03922b)

#流れ
1. Catalyst/IOS-XEでguestshellの設定
2. 環境を整える
3. Cisco Sparkのアカウント作成と、アクセストークンなど取得
4. Catalyst上でpythonスクリプトを作成（Cisco SparkにメッセージをPost）
5. Catalyst/IOS-XEでEEMの設定
6. 動作確認

# 1. Catalyst/IOS-XEでguestshellの設定

以下を参照。
[Cisco Catalyst IOS-XEでのPythonやBash](http://qiita.com/kikuta1978/items/1739d7d7063a20b1736f)

# 2. 環境を整える

guestshellと外部とのネットワーク接続は、いわゆるフロントポートはサポートされておらず、マネジメントポートのみとなっており、注意が必要。

```cisco:設定例
interface GigabitEthernet0/0
 vrf forwarding Mgmt-vrf
 ip address <ipaddress> <mask>
!
ip route vrf Mgmt-vrf 0.0.0.0 0.0.0.0 <mgmt-gateway>
```

外部との疎通確認OK。

```
[guestshell@guestshell ~]$ sudo ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=52 time=3.00 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=52 time=2.46 ms
```

ネームサーバを登録。

```
[guestshell@guestshell ~]$ cat /etc/resolv.conf 
nameserver <ipaddress>
```

名前解決もOK。

```
[guestshell@guestshell ~]$ sudo ping www.cisco.com
PING origin-www.cisco.com (72.163.4.161) 56(84) bytes of data.
64 bytes from www1.cisco.com (72.163.4.161): icmp_seq=1 ttl=235 time=300 ms
64 bytes from www1.cisco.com (72.163.4.161): icmp_seq=2 ttl=235 time=292 ms
```

PIPは最初から入っている。Requestsモジュールくらいは入れておく。

```
[guestshell@guestshell ~]$ sudo -E  pip install requests
```

確認。

```
[guestshell@guestshell ~]$ sudo pip list install
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
certifi (2017.7.27.1)
chardet (3.0.4)
idna (2.5)
pip (9.0.1)
requests (2.18.2)
setuptools (22.0.5)
urllib3 (1.22)
```

# 3. Cisco Sparkのアカウント作成と、アクセストークンなど取得

Cisco Sparkの簡単な説明と、アクセストークン取得などは、以下の記事参照。
[AnsibleでCisco Sparkに投稿 - cisco_spark](http://qiita.com/kikuta1978/items/d7b2509bcf60b9449848)

# 4. Catalyst上でpythonスクリプトを作成（Cisco SparkにメッセージをPost）

スイッチのbootflash:は、/flashにマウントされている。/flashに移動し、自分のディレクトリを作ってスクリプトを作成する。

```
[guestshell@guestshell ~]$ pwd
/home/guestshell
[guestshell@guestshell ~]$ cd /flash
[guestshell@guestshell flash]$ mkdir kikuta
[guestshell@guestshell flash]$ cd kikuta
[guestshell@guestshell kikuta]$ touch spark_post.py
[guestshell@guestshell kikuta]$ ls
spark_post.py
```

ローカルでスクリプトを作って、スイッチのbootflashに転送しても良いし、簡単なものなら、guestshell上のviで作っても良い。Cat9300ならyumでエディタも簡単にインストールできるので、もうちょっと便利そう。

## テストスクリプトのポイント

- Cisco Sparkのスペースに、メッセージをPostするだけの簡単なもの
- メッセージはスクリプトに引数で渡せるようにして、IOSコンフィグで書くことにする
- Cat3850はPython2.7しかサポートしないので、printとか注意（泣）
- Cat9300はPython3もサポートするらしい
- アクセストークンやルームIDは自分のものに置き換える


```python:spark_post.py 
[guestshell@guestshell kikuta]$ cat spark_post.py 
import requests
import sys

ACCESS_TOKEN = "<my_access_token>"
ROOM_ID = "<my_room_id>"
YOUR_MESSAGE = sys.argv[1]

#ヘッダ作成
def setHeaders():
    accessToken_hdr = 'Bearer ' + ACCESS_TOKEN
    spark_header = {'Authorization': accessToken_hdr, 'Content-Type': 'application/json; charset=utf-8'}
    return spark_header

#スペースにメッセージをポスト
def postMsg(the_header,roomId,message):
    message = '{"roomId":"' + roomId + '","text":"' + message +'"}'
    uri = 'https://api.ciscospark.com/v1/messages'
    resp = requests.post(uri, data=message, headers=the_header)
    print resp

header=setHeaders()
postMsg(header,ROOM_ID,YOUR_MESSAGE)
```

ゲストシェル上で動作確認。引数は適当に書く。

```
[guestshell@guestshell kikuta]$ python ./spark_post.py "Hello from Cat3850"
<Response [200]>
```
いい感じに投稿できた。

![SS 2017-07-28 8.44.20.png](https://qiita-image-store.s3.amazonaws.com/0/157325/3a157a33-6966-43ff-34d1-487dccb8ecb8.png)

# 5. Catalyst/IOS-XEでEEMの設定

[前回](http://qiita.com/kikuta1978/items/1739d7d7063a20b1736f)はNONEイベントを使って手動でテストしたが、今回はSyslogイベントの例。正規表現にマッチするSyslogをトリガーにイベント発行し、EEMアクションとして先ほどのPythonスクリプトを実行。とりあえずどうでもいいLoopbackでも作って、shut/no shutする。

```
interface Loopback100
 ip address 1.1.1.1 255.255.255.255
```

EEMでは、発行したイベントごとに、システムがビルトイン変数を返してくれるので、まるごとSyslogを取り出してSparkに投げたかったけど、コマンドの引数に入れることは失敗。ビルトイン変数は何かと便利なので、ついでにメモ。

[Embedded Event Manager Built-In Environment Variables Used in EEM Applets](http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/eem/configuration/12-4t/eem-12-4t-book/eem-policy-cli.html#GUID-48CB6E8C-F456-4398-8B66-CC499331CB49)

今回はインターフェースUp/Downが発生したので、確認してね。っていうことと、ついでにNMSのダッシュボードも誘導する感じのサンプルにしてみた。イベントは様々作れるので、例えばピアが切れたとか、トンネルが不安定になったとか、遠くのサーバまでの遅延が閾値を超えたとか、そういうトリガーごとに誘導するダッシュボードやツールをポストするなども有りかもしれない。インシデントチケットシステムのチケット作成するとか。

（205と206が冗長だけど、サンプルということで..）

```
Cat3850-3#sh run | sec event manager
event manager applet syslog
 event syslog pattern "%LINEPROTO-5-UPDOWN:"
 action 100 syslog msg "Syslog ## $_syslog_msg ## by EEM"
 action 200 cli command "enable"
 action 205 cli command "guestshell run python /bootflash/kikuta/spark_post.py Interface_UpDownEvent_Detected"
 action 206 cli command "guestshell run python /bootflash/kikuta/spark_post.py Please_Confirm_theEvent_Soon"
 action 208 cli command "guestshell run python /bootflash/kikuta/spark_post.py https://10.71.154.112/"
```

# 6. 動作確認

EEMの挙動確認用のデバッグをONにしておく。

```
Cat3850-3#debug event manager action cli 
Debug EEM action cli debugging is on
```

```
Cat3850-3#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
Cat3850-3(config)#int loopback 100
Cat3850-3(config-if)#no shut
Cat3850-3(config-if)#end
Cat3850-3#
Cat3850-3#
*Jul 27 16:45:31.287: %SYS-5-CONFIG_I: Configured from console by console
*Jul 27 16:45:32.727: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback100, changed state to up
*Jul 27 16:45:32.728: %LINK-3-UPDOWN: Interface Loopback100, changed state to up
*Jul 27 16:45:32.738: %HA_EM-6-LOG: syslog: EEM Syslog 
*Jul 27 16:45:32.727: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback100, changed state to up by EEM
*Jul 27 16:45:32.739: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : CTL : cli_open called.
*Jul 27 16:45:32.742: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : Cat3850-3>
*Jul 27 16:45:32.743: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : IN  : Cat3850-3>enable
*Jul 27 16:45:32.755: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : Cat3850-3#
*Jul 27 16:45:32.756: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : IN  : Cat3850-3#guestshell run python /bootflash/kikuta/spark_post.py Interface_UpDownEvent_Detected
*Jul 27 16:45:39.782: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : <Response [200]>
*Jul 27 16:45:39.783: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : 
*Jul 27 16:45:39.783: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : 
*Jul 27 16:45:39.784: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : Cat3850-3#
*Jul 27 16:45:39.784: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : IN  : Cat3850-3#guestshell run python /bootflash/kikuta/spark_post.py Please_Confirm_theEvent_Soon
*Jul 27 16:45:46.716: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : <Response [200]>
*Jul 27 16:45:46.716: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : 
*Jul 27 16:45:46.717: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : 
*Jul 27 16:45:46.717: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : OUT : Cat3850-3#
*Jul 27 16:45:46.717: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : IN  : Cat3850-3#guestshell run python /bootflash/kikuta/spark_post.py https://10.71.154.112/
*Jul 27 16:45:52.795: %HA_EM-6-LOG: syslog : DEBUG(cli_lib) : : CTL : cli_close called.
*Jul 27 16:45:52.798: 
*Jul 27 16:45:52.798: tty is now going through its death sequence
```

いい感じです。

![SS 2017-07-28 8.57.40.png](https://qiita-image-store.s3.amazonaws.com/0/157325/d5cca9fe-3c1b-6c32-7c0f-e61841304234.png)

以上です。なかなか応用範囲が広そうですし、しばらく遊べそうです。

# 参考
[Programmability Configuration Guide, Cisco IOS XE Everest 16.5.1a (Catalyst 3850 Switches)](http://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst3850/software/release/16-5/configuration_guide/prog/b_165_prog_3850_cg.html)