これはなに?
SIMフリー版iPhoneを買ったので、SoftBankからIIJmioにMNPした筆者が、残りクーポン量を知るべく、Perlを使って作ったいろいろの話。をする予定で、書き始めたけれど、とりあえず、ZabbixテンプレートとPerlスクリプトだけ張った状況のヒドい文書。
前提
- Zabbix {Server, Sender}のインストールが完了している
- Perlのモジュールが足りなければ自分で追加する根性
- 筆者は、動けばいいと思って書いたので、コードの汚さは気にしない
そもそもIIJmioのAPIって?
IIJmioクーポンスイッチAPI
に書かれている仕様を読むと、残りクーポン量は、有効期限(expire)やクーポン種別(bundle, topup)別に取得出来る。
データ設計
クーポン種別毎有効期限毎にデータが取得出来るが、そもそも有効期限は毎月変わっていくので、キーとして最初から登録するのには向かない。でも、得られる値をそのまま格納しておいた方が、あとから分析したくなったときに、なにかとうれしいよね。
つまり、AutoDiscoveryでキーを作成して、そのキーに対してデータを登録していく必要がある。
そこで、参考にしたページ
- ZABBIX SENDER を利用したAutoDiscoveryの方法
- LLD(ローレベルディスカバリ)を弄り倒せ、zabbix_senderを併用してらくらく可視化
- IIJmioクーポンスイッチAPIを使って使用量グラフ作成
こんなグラフが出来ます
30分おきにcronから起動するように設定しておくと、以下のようなグラフを得ることが出来ます
クーポン残量の話のはずだったのに、パケット利用量のグラフですが、まぁ、似たようなもんです。
あとは、若い者同士で……
Perlスクリプトは前半でクーポン残量を、後半で利用パケット料を利用している電話番号別に取得しています
Zabbixテンプレートも、ミニマムスタートプランを複数契約している人などは、契約毎にhost discoveryでhostを作っていくと、キレイにまとまるんじゃ無いかと思いますが、わたし自身がファミリーシェアプランを1契約しか持っていないので、そこまで汎用的に作る気力がありませんでした。
Perl スクリプト
#!/usr/bin/env perl
use strict;
use utf8;
use v5.10;
use Data::Dumper;
use JSON -support_by_pp;
use LWP;
use Time::Local 'timelocal';
my $ZABBIX_SENDER = "/usr/bin/zabbix_sender";
my $ZABBIX_HOST = "iijmio";
my $ZABBIX_SERVER = "localhost";
my $developerid = "<取得してね>";
my $usertoken = "<取得してね>";
my @coupon_discovery_data;
my @packet_discovery_data;
my %hdoServiceCode2num;
my $now =timelocal(localtime());
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
= localtime(time);
$year += 1900;
$mon += 1;
my $today = sprintf("%04d%02d%02d", $year, $mon , $mday);
my $ua = LWP::UserAgent->new;
my $url="https://api.iijmio.jp/mobile/d/v1/coupon/";
my $req = HTTP::Request->new(GET => "$url");
$req->header("X-IIJmio-Developer" => "$developerid");
$req->header("X-IIJmio-Authorization" => "$usertoken");
my $res= $ua->request($req);
my $coupon = decode_json( $res->content );
unless ($coupon->{"returnCode"} = "OK"){
print "Not OK";
exit;
}
my $total ;
foreach my $item (@{$coupon->{"couponInfo"}->[0]->{"coupon"}}){
$total += $item->{"volume"};
push @coupon_discovery_data, {
"{#CPNTYPE}" => $item->{"type"} ,
"{#CPNEXPIRE}" => $item->{"expire"}
};
}
push @coupon_discovery_data, {
"{#CPNTYPE}" => 'TOTAL',
"{#CPNEXPIRE}" => 'TOTAL',
};
push @{$coupon->{"couponInfo"}->[0]->{"coupon"}},{
'type' => 'TOTAL',
'expire' => 'TOTAL',
'volume' => $total
};
my $coupon_discovery = encode_json( {"data" => \@coupon_discovery_data});
my @cmd;
@cmd = (
$ZABBIX_SENDER,
"-z",
$ZABBIX_SERVER,
"-s",
$ZABBIX_HOST,
"-k iijmio.coupon.discovery",
"-o",
"'".$coupon_discovery."'"
);
system(join(" ",@cmd));
foreach my $item (@{$coupon->{"couponInfo"}->[0]->{"hdoInfo"}}){
$hdoServiceCode2num{$item->{"hdoServiceCode"}} = $item->{"number"};
push @packet_discovery_data, {
"{#NUMBER}" => $item->{"number"} ,
};
}
my $packet_discovery = encode_json( {"data" => \@packet_discovery_data});
@cmd = (
$ZABBIX_SENDER,
"-z",
$ZABBIX_SERVER,
"-s",
$ZABBIX_HOST,
"-k iijmio.packet.discovery",
"-o",
"'".$packet_discovery."'"
);
#say join(" ",@cmd);
system(join(" ",@cmd));
sleep 30;
open( SENDER ,"| $ZABBIX_SENDER -z $ZABBIX_SERVER -T -i -")
|| die "can't fork: $!";
foreach my $item (@{$coupon->{"couponInfo"}->[0]->{"coupon"}}){
local $SIG{PIPE} = sub { die "$ZABBIX_SENDER pipe broke" };
my $key =
"\"iijmio.coupon.rest[".
$item->{"type"} .
",".
$item->{"expire"}.
"]\"";
# Each line of the input file must contain 4 whitespace delimited entries:
# <hostname> <key> <timestamp> <value>.
print SENDER join(" ",( $ZABBIX_HOST,$key,$now,$item->{"volume"},)),"\n";
}
$url="https://api.iijmio.jp/mobile/d/v1/log/packet/";
$req = HTTP::Request->new(GET => "$url");
$req->header("X-IIJmio-Developer" => "$developerid");
$req->header("X-IIJmio-Authorization" => "$usertoken");
$res= $ua->request($req);
my $packet = decode_json( $res->content );
foreach my $hdoinfo (@{$packet->{"packetLogInfo"}->[0]->{"hdoInfo"}}){
my $telnum = $hdoServiceCode2num{$hdoinfo->{"hdoServiceCode"}};
foreach my $packetlog ( @{$hdoinfo->{"packetLog"}} ){
my $date = $packetlog->{"date"};
my $y = substr($date,0,4);
my $m = substr($date,4,2);
my $d = substr($date,6,2);
my $t = timelocal(59,59,23,$d,$m-1,$y-1900);
next if ($now - $t > 4000);
if ( $date eq $today ){ $t = $now};
foreach my $w ("withCoupon","withoutCoupon"){
local $SIG{PIPE} = sub { die "$ZABBIX_SENDER pipe broke" };
my $key =
"\"iijmio.packets.used[".
$telnum .
",".
$w.
"]\"";
# Each line of the input file must contain
# 4 whitespace delimited entries:
# <hostname> <key> <timestamp> <value>.
print SENDER join(" ",
( $ZABBIX_HOST,$key,$t,$packetlog->{$w},)
),
"\n";
}
}
}
close SENDER || die "bad $ZABBIX_SENDER: $! $?";
exit;
Zabbix側テンプレート
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>3.2</version>
<date>2017-01-31T15:55:24Z</date>
<groups>
<group>
<name>iijmio</name>
</group>
<group>
<name>Templates</name>
</group>
</groups>
<templates>
<template>
<template>Template IIJmio mobile</template>
<name>Template IIJmio mobile</name>
<description/>
<groups>
<group>
<name>iijmio</name>
</group>
<group>
<name>Templates</name>
</group>
</groups>
<applications>
<application>
<name>Coupon</name>
</application>
<application>
<name>Packets</name>
</application>
</applications>
<items/>
<discovery_rules>
<discovery_rule>
<name>coupon discovery rule</name>
<type>2</type>
<snmp_community/>
<snmp_oid/>
<key>iijmio.coupon.discovery</key>
<delay>0</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<delay_flex/>
<params/>
<ipmi_sensor/>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<filter>
<evaltype>0</evaltype>
<formula/>
<conditions/>
</filter>
<lifetime>30</lifetime>
<description/>
<item_prototypes>
<item_prototype>
<name>Rest of Coupon {#CPNTYPE} / {#CPNEXPIRE}</name>
<type>2</type>
<snmp_community/>
<multiplier>1</multiplier>
<snmp_oid/>
<key>iijmio.coupon.rest[{#CPNTYPE},{#CPNEXPIRE}]</key>
<delay>0</delay>
<history>190</history>
<trends>365</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units>B</units>
<delta>0</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1048576</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>Coupon</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<application_prototypes/>
</item_prototype>
</item_prototypes>
<trigger_prototypes/>
<graph_prototypes/>
<host_prototypes/>
</discovery_rule>
<discovery_rule>
<name>iijmio Packet discovery</name>
<type>2</type>
<snmp_community/>
<snmp_oid/>
<key>iijmio.packet.discovery</key>
<delay>0</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<delay_flex/>
<params/>
<ipmi_sensor/>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<filter>
<evaltype>0</evaltype>
<formula/>
<conditions/>
</filter>
<lifetime>30</lifetime>
<description/>
<item_prototypes>
<item_prototype>
<name>packet used {#NUMBER} with Coupon</name>
<type>2</type>
<snmp_community/>
<multiplier>1</multiplier>
<snmp_oid/>
<key>iijmio.packets.used[{#NUMBER},withCoupon]</key>
<delay>0</delay>
<history>190</history>
<trends>365</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units>B</units>
<delta>0</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1048576</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>Packets</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<application_prototypes/>
</item_prototype>
<item_prototype>
<name>packet used {#NUMBER} without Coupon</name>
<type>2</type>
<snmp_community/>
<multiplier>1</multiplier>
<snmp_oid/>
<key>iijmio.packets.used[{#NUMBER},withoutCoupon]</key>
<delay>0</delay>
<history>190</history>
<trends>365</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units>B</units>
<delta>0</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1048576</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>Packets</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<application_prototypes/>
</item_prototype>
</item_prototypes>
<trigger_prototypes/>
<graph_prototypes/>
<host_prototypes/>
</discovery_rule>
</discovery_rules>
<httptests/>
<macros/>
<templates/>
<screens/>
</template>
</templates>
</zabbix_export>