blob: 61b693a9f3a3b275d04ea2ed56ad7459e40791f6 [file] [log] [blame]
#
# Net-SNMP perl plugin for Haproxy
# Version 0.27
#
# Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
#
# 1. get a variable from stat:
# 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid
# type: 0->frontend, 1->backend, 2->server
#
# 2. get a variable from info
# 1.3.6.1.4.1.29385.106.2.$req.$varnr
#
# TODO:
# - implement read timeout
#
use NetSNMP::agent (':all');
use NetSNMP::ASN qw(:all);
use IO::Socket::UNIX;
use strict;
my $agent = new NetSNMP::agent('Name' => 'Haproxy');
my $sa = "/var/run/haproxy.stat";
use constant OID_HAPROXY => '1.3.6.1.4.1.29385.106';
use constant OID_HAPROXY_STATS => OID_HAPROXY . '.1';
use constant OID_HAPROXY_INFO => OID_HAPROXY . '.2';
my $oid_stat = new NetSNMP::OID(OID_HAPROXY_STATS);
my $oid_info = new NetSNMP::OID(OID_HAPROXY_INFO);
use constant STATS_PXNAME => 0;
use constant STATS_SVNAME => 1;
use constant STATS_IID => 27;
use constant STATS_SID => 28;
use constant STATS_TYPE => 32;
use constant FIELD_INDEX => 10001;
use constant FIELD_NAME => 10002;
my %info_vars = (
0 => 'Name',
1 => 'Version',
2 => 'Release_date',
3 => 'Nbproc',
4 => 'Process_num',
5 => 'Pid',
6 => 'Uptime',
7 => 'Uptime_sec',
8 => 'Memmax_MB',
9 => 'Ulimit-n',
10 => 'Maxsock',
11 => 'Maxconn',
12 => 'CurrConns',
);
sub find_next_stat_id {
my($type, $field, $proxyid, $sid) = @_;
my $obj = 1 << $type;
my $np = -1;
my $nl = -1;
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
next if !$sock;
print $sock "show stat -1 $obj -1\n";
while(<$sock>) {
chomp;
my @d = split(',');
last if !$d[$field] && $field != FIELD_INDEX && $field != FIELD_NAME && /^#/;
next if /^#/;
next if $d[STATS_TYPE] != $type;
next if ($d[STATS_IID] < $proxyid) || ($d[STATS_IID] == $proxyid && $d[STATS_SID] <= $sid);
if ($np == -1 || $d[STATS_IID] < $np || ($d[STATS_IID] == $np && $d[STATS_SID] < $nl)) {
$np = $d[STATS_IID];
$nl = $d[STATS_SID];
next;
}
}
close($sock);
return 0 if ($np == -1);
return "$type.$field.$np.$nl"
}
sub haproxy_stat {
my($handler, $registration_info, $request_info, $requests) = @_;
for(my $request = $requests; $request; $request = $request->next()) {
my $oid = $request->getOID();
$oid =~ s/$oid_stat//;
$oid =~ s/^\.//;
my $mode = $request_info->getMode();
my($type, $field, $proxyid, $sid, $or) = split('\.', $oid, 5);
next if $type > 2 || defined($or);
if ($mode == MODE_GETNEXT) {
$type = 0 if !$type;
$field = 0 if !$field;
$proxyid = 0 if !$proxyid;
$sid = 0 if !$sid;
my $nextid = find_next_stat_id($type, $field, $proxyid, $sid);
$nextid = find_next_stat_id($type, $field+1, 0, 0) if !$nextid;
$nextid = find_next_stat_id($type+1, 0, 0, 0) if !$nextid;
if ($nextid) {
($type, $field, $proxyid, $sid) = split('\.', $nextid);
$request->setOID(sprintf("%s.%s", OID_HAPROXY_STATS, $nextid));
$mode = MODE_GET;
}
}
if ($mode == MODE_GET) {
next if !defined($proxyid) || !defined($type) || !defined($sid) || !defined($field);
my $obj = 1 << $type;
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
next if !$sock;
print $sock "show stat $proxyid $obj $sid\n";
while(<$sock>) {
chomp;
my @data = split(',');
last if !defined($data[$field]) && $field != FIELD_INDEX && $field != FIELD_NAME;
if ($proxyid) {
next if $data[STATS_IID] ne $proxyid;
next if $data[STATS_SID] ne $sid;
next if $data[STATS_TYPE] ne $type;
}
if ($field == FIELD_INDEX) {
$request->setValue(ASN_OCTET_STR,
sprintf("%s.%s", $data[STATS_IID],
$data[STATS_SID]));
} elsif ($field == FIELD_NAME) {
$request->setValue(ASN_OCTET_STR,
sprintf("%s/%s", $data[STATS_PXNAME],
$data[STATS_SVNAME]));
} else {
$request->setValue(ASN_OCTET_STR, $data[$field]);
}
close($sock);
last;
}
close($sock);
next;
}
}
}
sub haproxy_info {
my($handler, $registration_info, $request_info, $requests) = @_;
for(my $request = $requests; $request; $request = $request->next()) {
my $oid = $request->getOID();
$oid =~ s/$oid_info//;
$oid =~ s/^\.//;
my $mode = $request_info->getMode();
my($req, $nr, $or) = split('\.', $oid, 3);
next if $req >= 2 || defined($or);
if ($mode == MODE_GETNEXT) {
$req = 0 if !defined($req);
$nr = -1 if !defined($nr);
if (!defined($info_vars{$nr+1})) {
$req++;
$nr = -1;
}
next if $req >= 2;
$request->setOID(sprintf("%s.%s.%s", OID_HAPROXY_INFO, $req, ++$nr));
$mode = MODE_GET;
}
if ($mode == MODE_GET) {
next if !defined($req) || !defined($nr);
if ($req == 0) {
next if !defined($info_vars{$nr});
$request->setValue(ASN_OCTET_STR, $info_vars{$nr});
next;
}
if ($req == 1) {
next if !defined($info_vars{$nr});
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
next if !$sock;
print $sock "show info\n";
while(<$sock>) {
chomp;
my ($key, $val) = /(.*):\s*(.*)/;
next if $info_vars{$nr} ne $key;
$request->setValue(ASN_OCTET_STR, $val);
last;
}
close($sock);
}
}
}
}
$agent->register('Haproxy stat', OID_HAPROXY_STATS, \&haproxy_stat);
$agent->register('Haproxy info', OID_HAPROXY_INFO, \&haproxy_info);