はじめに
前回の続きです。
参考:
シスコの普及型スイッチCatalystやルータの新しいOS(IOS-XE)で動くコンテナ上で、PythonやBashがサポートされた
Cisco Catalyst IOS-XEでのPythonやBash
スイッチ上のPythonスクリプトは、IOSが内部で検出するイベントを元に任意のタイミングで自動で発行できることもわかった(EEM:Embedded Event Managerを使った発行)。さらに、EEMはPythonスクリプトで記述できることもわかった。後者の二つは似ているが、厳密には異なる。今回は、前者の動作ログ。今回も、Catalyst3850を利用。
(本当はCatalyst9300でやりたい。3850はMIPS CPU、9300はx86など、何かと制約が少ないと思われるため。)
参考:
Cisco IOS EEMを使ったTclスクリプトの実行
#流れ
- Catalyst/IOS-XEでguestshellの設定
- 環境を整える
- Cisco Sparkのアカウント作成と、アクセストークンなど取得
- Catalyst上でpythonスクリプトを作成(Cisco SparkにメッセージをPost)
- Catalyst/IOS-XEでEEMの設定
- 動作確認
1. Catalyst/IOS-XEでguestshellの設定
以下を参照。
Cisco Catalyst IOS-XEでのPythonやBash
2. 環境を整える
guestshellと外部とのネットワーク接続は、いわゆるフロントポートはサポートされておらず、マネジメントポートのみとなっており、注意が必要。
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
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は自分のものに置き換える
[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]>
いい感じに投稿できた。
5. Catalyst/IOS-XEでEEMの設定
前回は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
今回はインターフェース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
いい感じです。
以上です。なかなか応用範囲が広そうですし、しばらく遊べそうです。
参考
Programmability Configuration Guide, Cisco IOS XE Everest 16.5.1a (Catalyst 3850 Switches)