munin のプラグイン

昔、MRTGでいろいろなグラフを作っては、サーバーの投資の資料に使っていました。
「こんな高価なもの、ほんとに必要なの。もし必要だったら、その台数でほんとに間に合うの?」
厳しい管理職でなくても、上司なら提案した部下に当然聞く内容です。
「うちは1台も無いので、最低でも1台は必要です。」
とか言えたころは簡単だったのですが、仕事が増えて足りなくなり台数を増やす時期に入ると、いろいろと準備が必要になります。

 

MRTGは、簡単な数値さえ取れれば、なんでもグラフにすることができました。ただし基本は前回との差分をグラフ化するもので、ネットワーク機器に流れるパケットの変化などは簡単に設定できます。数値そのものをグラフ化する場合でも、設定ファイルを変えるだけで慣れてしまえば簡単だったという印象でした。でも、融通が利かず、それなりに苦労したような気がします。

さて、今は、サーバーのリソースをグラフ化するのに向いている munin を使っています。MRTG は、いっしょにインストールするライブラリの量が多く、バージョンによってはデフォルトでは入らないケースもあり、最初のうちは苦労しました。その点 munin もいっしょで、OSが古いせいか Perl のライブラリの追加は yum だけではできず、マニュアルで rpm をダウンロードしてインストールしました。そうやってせっかく設定した munin なんで、できるだけ使っていきたいと思っています。

そうした中、ネットワーク機器の監視にも使いたい、と思ったのですが、差分を計算するプラグインが必要になりました。このプラグインは、後からいろいろと手を入れたい管理者には、いい仕様だと思います。

 

<補足>
後から、こんなプラグインを作る必要はなかったと気がつきました。グラフの config で、.type に COUNTER を指定すれば、前回からの差分を使ってグラフを描いてくれます。もっと、がんばってドキュメントを探せばよかった。
とりあえず、下のスクリプトはやめて、プラグインを作りなおす予定です。(2016/8/26)

 

 

今回作成するプラグインの基本は、munin が動いているサーバーのどこかに前回の数値を格納したファイルを残しておいて、それとの差分を毎回プラグインで計算させればいいというものです。最初は MRTG のようにグラフ生成に使うデータを参照しようか、と思ったのですが、どうもバイナリーデータになっていて、専用のツールが必要。しかも、このデータから最新の数値だけ取ってくるだけでもちょっと面倒みたい。じゃ、ということで、ruby で簡単に作ってしまえ、ということにしました。サンプル用で作ってみたのが下記のスクリプトです。
テストではいい感じに動作しているようです。

#!/usr/bin/ruby
#
# ○○○○のスイッチの通信量
#
# .1.3.6.1.2.1.2.2.1.11.24 24ポートが受信したユニキャストパケットの総数
# .1.3.6.1.2.1.2.2.1.17.24 24ポートが送信したユニキャストパケットの総数

past_f = "/tmp/????.past_f"
limit = 600
valname = [
  [ 0, "InPkts",  ".1.3.6.1.2.1.2.2.1.11.24 " ],
  [ 1, "OutPkts", ".1.3.6.1.2.1.2.2.1.17.24 " ],
]
snmpwalk = "/usr/bin/snmpwalk -v 2c -c ???? "
target_ip = "####.####.####.#### "
awk_cmd = "| awk -F \":\" '{gsub(\" \",\"\",$4);printf($4);}'"
n_value = Array.new
p_value = Array.new
#
# 引数 config に対する出力
if ARGV[0] == "config" then
  print("graph_title SW_InOut_Packets (????)\n")
  print("graph_category Switch InOut\n")
  valname.each { |vn|
    print( vn[1], ".label ", vn[1], "\n")
  }
else
#
#前回サーバーに保管したデータ格納ファイルの有無とタイムスタンプをチェック
  if File.exist?( past_f ) then
    now = Time.new.to_i
    past = File.mtime( past_f ).to_i
    f_sabun = now - past
    if f_sabun > limit then
      w_sw = 1;
    else
      w_sw = 0;
    end
  else
    w_sw = 1
  end
#
#SNMPでパケット数を取得する
  valname.each { |vn|
    snmp_cmd = snmpwalk + target_ip + vn[2] + awk_cmd
    n_value[vn[0]] = `#{snmp_cmd}`.to_i
  }
#
#前回からのパケット数の差分値を出力する
  if w_sw == 1 then
    valname.each { |vn|
      print( vn[1], ".value 0\n")
    }
  else
    read_cmd = "cat " + past_f
    txt = `#{read_cmd}`
    p_value = txt.split("\n")
    valname.each { |vn|
      sabun = n_value[vn[0]] - p_value[vn[0]].to_i
      print( vn[1], ".value ", sabun, "\n")
    }
  end
#
# 今のパケット数をファイルに書き込み
  f=open( past_f, "w")
  n_value.each { |nv|
    outs = nv.to_s + "\n"
    f.puts( outs )
  }
  f.close
end

せっかく ruby で作るのだから効率よく、なんて思ったのですが、後からあれもいるしこれもいる、
なんて感じで作っていったら、意外と読みにくいコードになってしまいました。
なんとか、変数だけ変えて応用が利くようと思ったのですが、どうでしょうね。

PAK86_smonitatocode20140517_TP_V