diff options
Diffstat (limited to 'admin/netsnmp-perl/haproxy.pl')
-rw-r--r-- | admin/netsnmp-perl/haproxy.pl | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/admin/netsnmp-perl/haproxy.pl b/admin/netsnmp-perl/haproxy.pl new file mode 100644 index 0000000..64684ad --- /dev/null +++ b/admin/netsnmp-perl/haproxy.pl @@ -0,0 +1,249 @@ +# +# Net-SNMP perl plugin for HAProxy +# Version 0.30 +# +# Copyright 2007-2010 Krzysztof Piotr Oledzki <ole@ans.pl> +# +# 1. get a variable from "show stat": +# 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid +# type: 0->frontend, 1->backend, 2->server, 3->socket +# +# 2. get a variable from "show 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 => 'Maxpipes', + 13 => 'CurrConns', + 14 => 'PipesUsed', + 15 => 'PipesFree', + 16 => 'Tasks', + 17 => 'Run_queue', + 18 => 'node', + 19 => 'description', +); + +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 > 3 || 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); + |