RTX1200の状態をMackerelに監視させる

More than 3 years have passed since last update.

12/3 Mackerelアドベントカレンダー 3日目です。

昨日は @daiksy さんによるエントリでした。

プロダクトとユーザの距離感について考えてみる

http://blog-ja.mackerel.io/entry/advent-calendar2015/day2

Mackerel のメール、毎回楽しく読んでます!



何したの?

 Mackerel 自体については、既に家の中のサーバーや VPS などを監視しており、agent 入れるだけでこんなにできるんだ、便利だなーというところで止まっていました。

 何か面白いことができないかな、と思っていたら、最近買って家に導入した RTX1200 (本当はIPX) というルーターが目に入ったので、以前から気になっていた API の使い方を調べて、実際にルーターのメトリックを Mackerel に集約してみました。

 RTX シリーズ、およびほかのいくつかのヤマハルーターでは、 Lua で書かれたスクリプトを実行することができます。また、ルーター専用の拡張命令セットがあり、 http もしゃべることができるので、この機能を利用しました。


前準備:プロキシを立てる

 RTX シリーズの Lua で使える rt.httprequest 命令は以下の特徴(注意点)があります。


  • https をサポートしていない( Mackerel API は https 必須)

  • リクエストヘッダのカスタマイズや追加が不可能

そのため、メトリック情報を送信するためには下記の目的でプロキシを用意する必要があります。おそらく、Lua で https 接続が可能になるモジュールを作って直接接続させることは出来なくはないと思いますが、使える命令が少なかったりルーターの内部ストレージの圧迫を招いたり、スクリプトの管理が困難になりそうなので諦めました。


  • http -> https のプロキシ

  • リクエストヘッダへ Mackerel API キー (X-Api-Key) を追加する

今回は、家のLAN側に Raspberry Pi を置き、 http 接続を nginx でプロキシさせるようにしました。以下のように雑に conf を書いていきます。

server {

listen 80;
server_name 適当に名前を付ける;
location / {
proxy_pass https://mackerel.io;
proxy_set_header X-Api-key (Mackerel で発行した API キー);
}
}

 プロキシ側にキー情報を持ち、これを経由すると無条件で API リクエストが可能になってしまってよろしくないため、プロキシはローカルネットワーク内に立てて、アクセス制限もしておくことを強くお勧めします。手順は割愛。

 余談ですが、このプロキシサーバ自体も mackerel-agent の ARM 版バイナリ を導入して監視しています。

IMG_20151202_212257.jpg

ルーターの上のラズパイ


ルーター用のホスト情報を登録する

http://help-ja.mackerel.io/entry/spec/api/v0#host-create に従って情報を登録します。最低限の情報でよいのであれば下記のような curl を投げるだけでよいはずです。このとき、返ってきた hostId を覚えておいてください

curl -X POST -H 'Content-type: application/json' -H 'X-Api-Key: <API KEY>' -d '{"name":"rtx1200","meta":{}}' https://mackerel.io/api/v0/hosts

後から情報を変更したい場合は hostId を指定して PUTします

curl -X PUT -H 'Content-type: application/json' -H 'X-Api-Key: <API KEY>' -d '{"name":"rtx.dolpen.local","displayName":"rtx1200","meta":{"agent-name":"dolpen-agent/0.0.1 (Revision20151127)","agent-revision":"20151127","agent-version":"0.0.1","block_device":{"rtfs":{"removable":"0","size":"16384"}},"cpu":[{"core_id":"0","cores":"1","mhz":"300.0","model_name":"MIPS"}],"memory":{"total":"131072kB"},"kernel":{"machine":"MIPS","name":"Yamaha","os":"Yamaha","release":"RTX1200 Rev.10.01.59","version":"Tue Aug 19 19:26:02 2014"}}}' https://mackerel.io/api/v0/hosts/<hostId>


ルーターに Lua スクリプトを仕込む

以下のスクリプトの設定値を適切に置き換えて、RTXに送信します。


-------------------------- ## 設定値 ##--------------------------------

-- 監視間隔(1 - 864000 秒)
-- 5分以上の間隔にすると Mackerel の Connectivity アラートが上がるので監視から外すか5分未満にする
idle_time = 180

-- os.time と unix time のオフセット(秒)
os_time_offset = 315532800;

-- Mackerel API に向けた http プロキシのエンドポイントURL
proxy_tsdb = "http://proxy_server/api/v0/tsdb"

-- Mackerel で実行端末用に作成した hostId
-- @see http://help-ja.mackerel.io/entry/spec/api/v0#host-create
host = "**********"

---------------------- ## 設定値ここまで ##----------------------------

------------------------------------------------------------
-- ルーターのハードウェアリソースの使用状況を取得する関数 --
-- サンプルからありがたく拝借
------------------------------------------------------------
function rt_res_status(table)
local rtn, str
local cmd = "show environment"
rtn, str = rt.command(cmd)
if (rtn) and (str) then
for k, v in pairs(table) do
v.val = str:match(v.ptn)
if (v.val) then
v.val = tostring(v.val)
end
end
else
str = cmd .. "コマンド実行失敗\r\n\r\n"
end
return rtn, str
end

------------------------------------------------------------
-- Mackerel 向けの MetricValue API Post 文字列生成 --
-- @see http://help-ja.mackerel.io/entry/spec/api/v0#metric-value-post
------------------------------------------------------------
function make_post_text(host, time, table)
local a = "";
for k, v in pairs(table) do
a = a .. string.format("{\"hostId\":\"%s\",\"name\":\"%s\",\"value\":%s,\"time\":%d}", host, v.name, v.val, time) .. ","
end
return "[" .. string.sub(a,1,-2) .. "]"
end

------------------------------------------------------------
-- メインルーチン --
------------------------------------------------------------

-- ハードウェアリソース情報テーブル
local rt_res_tbl = {
cpu_5sec = { ptn = "(%d+)%%%(5sec%)", val = 0 , name = "custom.rtx.cpu.5sec"},
cpu_1min = { ptn = "(%d+)%%%(1min%)", val = 0 , name = "custom.rtx.cpu.1min"},
cpu_5min = { ptn = "(%d+)%%%(5min%)", val = 0 , name = "custom.rtx.cpu.5min"},
memory = { ptn = "(%d+)%% used", val = 0 , name = "custom.rtx.memory.usage"},
packet_small = { ptn = "(%d+)%%%(small%)", val = 0 , name = "custom.rtx.packetbuff.small"},
packet_middle = { ptn = "(%d+)%%%(middle%)", val = 0 , name = "custom.rtx.packetbuff.middle"},
packet_large = { ptn = "(%d+)%%%(large%)", val = 0 , name = "custom.rtx.packetbuff.large"},
packet_huge = { ptn = "(%d+)%%%(huge%)", val = 0 , name = "custom.rtx.packetbuff.huge"},
temp = { ptn = "筐体内温度%(℃%): (%d+)", val = 0 , name = "custom.rtx.temperature.body"}
}

-- HTTPリクエスト用テーブル
local http_req_tbl = {
url = proxy_tsdb,
method = "POST",
content_type = "application/json"
}

local rtn, str, num, now

while (true) do
-- リソースの取得
rtn, str = rt_res_status(rt_res_tbl)
-- 現在時刻をエポック秒にする
now = os.time() + os_time_offset
-- コマンド失敗時は処理しない(Mackerel の Connectivity アラートを上げさせる)
if (rtn) then
-- リクエストを発行
http_req_tbl.post_text = make_post_text(
host,
now,
rt_res_tbl
)
rt.httprequest(http_req_tbl)
-- http_res_tbl = rt.httprequest(http_req_tbl)
-- print(http_req_tbl.post_text)
-- print(http_res_tbl.body)
end
rt.sleep(idle_time)
end

 内部でかなり強引に JSON を作って http で投げる Lua スクリプトです。os.time() が返す値は、 Lua の言語仕様上は実行するシステムに依存していて、その中身は不明なためあんまりエポック秒を作るのに使ってはいけないようでしたが、今回に限りオフセットを足し算したらうまく行きました。全てのルーターで同じオフセットにはならなそうですが。。。


Lua 実行 & スケジューリング

 最後に、ルーターに直接入って、管理者権限で以下のコマンドを発行しておきます

lua (Luaスクリプトファイル名)

schedule at 1 startup * lua (Luaスクリプトファイル名)

 スクリプト自体は一度動かしてしまえばスリープしながら無限ループで動くので、コマンドで起動して、再起動時に自動でコマンドが叩かれるようにしてしまえば後はノータッチで勝手に動きます。


Mackerel 側で適切にグラフ設定する

できた!

dd08e877574b65bccc466cfd23853291.png

 Mackerel 側で見栄えをいじっていくとそれっぽくなります。

 今は、僕が部屋にいるときに筐体の温度が高く、部屋にいなかったり寝ていたりするときは低くなっていくのを楽しく眺めています。

 あと、負荷が高かったり筐体の温度が高くなりすぎたときのために、アラートを設定して、Slack に流すようにしました。スマホにも Slack のクライアントを入れているので、何かあった場合はどこでも通知を受け取ることが出来ます。

97b85900cadcef2990ddbe294441fdc8.png

 これで年末年始に帰省しても安心ですね。


応用


  • ヤマハのルータであれば、RT(X) の他の機種や NVR 系でも同じスクリプトが使い回せる可能性があるようです。ただ、温度計がなかったり環境情報のメッセージフォーマットが違ったりするので、適宜スクリプト中の rt_res_tbl をコメントアウト、改変する必要がありそうです。

  • 今回は show environment コマンドで返ってくる値を取得して Mackerel に送っていますが、他のコマンドでも楽しいことがたくさんできそうです。



    • show ? で、サブコマンド一覧が出てきます

    • その中でも show status ? のサブコマンドを使うと、ステータスを表示できる各種インターフェースの一覧が出てきます

    • たとえば、show status lan1 と打てば、LAN1インターフェースの累計送受信パケット数などが出てくるので、 Lua スクリプトのループ内で差分を取得してループのインターバル時間で割ってあげれば使用帯域を計算したりできそうです




詰まったところ


ホストのメタ情報


  • どう登録するか困った(API ドキュメントに詳細項目書いてない...) ので調べました


    • 既に登録してあった VPS のホスト情報を見て、だいたいの当たりをつける


    • mackerel-agent のソース を読んで、どのコマンドの出力をどう加工しているかを確認する



できました

41ca390f8f24341f9efc9513da0ed5f7.png


参考

Mackerel API仕様(v0)

http://help-ja.mackerel.io/entry/spec/api/v0

mackerelio/mackerel-agent

https://github.com/mackerelio/mackerel-agent

Lua - ルーターの状態を報告する

http://jp.yamaha.com/products/network/solution/lua/script/alert/

Lua 向けヤマハルーター専用 API - HTTPライブラリ

http://www.rtpro.yamaha.co.jp/RT/docs/lua/rt_api.html#rt_httpreq

ヤマハルーターのハードウェア仕様(CPUとメモリの一覧)

http://www.rtpro.yamaha.co.jp/RT/hardware/cpu.html


明日は @senyoltw さんです!