Help us understand the problem. What is going on with this article?

シスコルータのチャットを自動化する

More than 3 years have passed since last update.

NetOpsCoding Advent Calendar 2016 12/16分の記事です。

背景

もともとChatOps系のネタで何をやろうかと考えていたのですが、IOS自身にもチャットに近い機能(sendコマンド)があることを思い出しました。

送信側がこれを実行すると
Router#send *
Enter message, end with CTRL/Z; abort with CTRL/C:
test message
^Z
Send message? [confirm]
Router#
受信側でこれが表示される
***
***
*** Message from tty1 to all terminals:
***
test message

で、このsendコマンドがとても使いづらいんです。

  • 発言の度にログインするのが非常に手間である。
  • ログインしてないと発言を受けることができない。
  • 過去のメッセージが記録されない。
  • 日本語や絵文字が使えない。
  • チャットだったらGUIの方が使いやすい。
  • アバター画像があると親近感あって良い。

なので、これらの問題を自動化その他もろもろで何とかしてみました。

成果物(Web UI部分)

chat.png

全然sendコマンドの面影がありませんが、バックエンドでは重要な役割を担っています。
裏の仕組みについては後述します。

CLI部分を完全に自動化したので、非常に快適にチャットができるようになりました。

https://github.com/tanksuzuki/cchat

構成

構成.png

Router(as a Database)

標準のsendではログイン中のユーザにしか発言できず、過去の発言は保存されません。
そのため、データを保持できる何かしらの場所が必要となります。

案1: Flashにファイルを置く

Flashにファイルを作って、 IOS.shで発言内容を記録してく方法です。
Cisco IOS シェル CLI モジュールの設定例

echoやcatで繋げる例
Router#echo test1 > flash:file1

Router#echo test2 > flash:file2

Router#cat flash:file1 flash:file2
test1test2Router#

なんか普通すぎて面白みに欠けるため、この案は不採用になりました。

案2: bannerに記録する

banner motd的なところに発言内容を追記していく方式です。
容量的に懸念があったので、ちょっと検証してみました。

motd容量チェック
Router(config)#banner ^
Enter TEXT message.  End with the character '^'.
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
----- 省略 -----
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567
Maximum Banner size 3000 bytes reached. Banner message is truncated
Router(config)#$23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
^
% Invalid input detected at '^' marker.

3000byteでアウト。容量的に辛いので、この案は不採用になりました。

案3: ログに記録する

sendは、ユーザに直接メッセージを送るだけでなく、ログに任意の文字列を出力させることもできます。

Router#send log hogehoge
Router#sh log | tail 1
Dec 12 2016 03:48:11: %SYS-7-USERLOG_DEBUG: Message from tty1(user id: hello@tanksuzuki.com): hogehoge

Router#

これは素晴らしい。

  • WriteもReadもコマンド化されてる。
  • バッファから溢れたログは自動破棄されるので管理が楽。
  • バッファを増やすことで、ある程度の量の発言を保持できる。

ということで、ログ領域をNoSQL的に使うことに決めました。
JSONを突っ込んでしまいましょう。

SSHクライアント

役割は2つです。

  • APIで渡されたメッセージを、ルータにログインしてsend logする。
  • APIでメッセージ取得要求を受けたら、ルータにログインしてsh logする。

メッセージ構造は下記の通り。
この構造体をJSON化してログに突っ込むんですが、send log時にダブルクォーテーションが削られてしまうため、全体をBase64化してJSON構文を保護しています。

cchat.go
type Message struct {
    ID    string `json:"id"`
    Date  string `json:"date"`
    Owner string `json:"owner"`
    Body  string `json:"body"`
}

下記は入れた結果です。

show_log
Dec 12 2016 04:28:35: %SYS-7-USERLOG_DEBUG: Message from tty1(user id: hello@tanksuzuki.com): eyJpZCI6IjZiN2YzZmQ2YTliZjM1ZWFkY2U5NjE1OGQ3YjEzYzI2ZjE0ZDM3ZDAiLCJkYXRlIjoiMjAxNi0xMi0xMlQwNDoyODozM1oiLCJvd25lciI6ImhlbGxvQHRhbmtzdXp1a2kuY29tIiwiYm9keSI6InRlc3QifQ==

API / Web UI

inputに入れた文章は、APIサーバのPOST /api/message経由で SSHクライアントに渡されます。
また、30秒ごとにAPIサーバのGET /api/messagesを叩いてメッセージ一覧を取得し、Riotで描画しています。

アバター画像はGravatarから取得しています。
Gravatarに登録しているメールアドレスを、SSHのユーザ名にすればOKです。

課題

大きなところで3点あります。

課題1: 発言データは揮発性

ログはメモリに乗っているだけなので、再起動すると揮発します。
ログ領域をDB化する以上、半ば最初から諦めていた部分ですが、できることなら何とかしたいです。

課題2: ログの文字数制限

ログ1行あたりの文字数上限が340文字でした。
それ以上の文字数をsend logしても、溢れた部分が削られるだけでコマンドとしては正常終了します。

長い文章を送るとJSONの後半部分が落ちて不良レコード化するため、現状だと半角40文字くらいまでがメッセージの上限になっています。

課題3: Read/Writeが遅すぎる

ストレスを感じるレベルで読み書きに時間がかかります。
ルータをDBにするのはやめた方が良いかもしれません。

今後について

まだ構想段階ですが、クライアントとDB(ルータ)の間に挟むコントローラ的なものがあれば劇的な改善が見込めそうです。

  • 複数のDB(ルータ)に対し、RAID5的にレコードを分散配置して耐障害性UP。
  • 長いレコードは1行に収まる程度に細切れにして分散配置し、コントローラ上で結合処理。
  • Writeを非同期化し、Readはコントローラ上のキャッシュで高速化する。

今度作ります。

tanksuzuki
インフラ屋だったりバックエンド屋だったりフロント屋だったり、色々です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away