blob: 61b693a9f3a3b275d04ea2ed56ad7459e40791f6 [file] [log] [blame]
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001#
2# Net-SNMP perl plugin for Haproxy
3# Version 0.27
4#
5# Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
6#
7# 1. get a variable from stat:
8# 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid
9# type: 0->frontend, 1->backend, 2->server
10#
11# 2. get a variable from info
12# 1.3.6.1.4.1.29385.106.2.$req.$varnr
13#
14# TODO:
15# - implement read timeout
16#
17
18use NetSNMP::agent (':all');
19use NetSNMP::ASN qw(:all);
20use IO::Socket::UNIX;
21
22use strict;
23
24my $agent = new NetSNMP::agent('Name' => 'Haproxy');
25my $sa = "/var/run/haproxy.stat";
26
27use constant OID_HAPROXY => '1.3.6.1.4.1.29385.106';
28use constant OID_HAPROXY_STATS => OID_HAPROXY . '.1';
29use constant OID_HAPROXY_INFO => OID_HAPROXY . '.2';
30
31my $oid_stat = new NetSNMP::OID(OID_HAPROXY_STATS);
32my $oid_info = new NetSNMP::OID(OID_HAPROXY_INFO);
33
34use constant STATS_PXNAME => 0;
35use constant STATS_SVNAME => 1;
36use constant STATS_IID => 27;
37use constant STATS_SID => 28;
38use constant STATS_TYPE => 32;
39
40use constant FIELD_INDEX => 10001;
41use constant FIELD_NAME => 10002;
42
43my %info_vars = (
44 0 => 'Name',
45 1 => 'Version',
46 2 => 'Release_date',
47 3 => 'Nbproc',
48 4 => 'Process_num',
49 5 => 'Pid',
50 6 => 'Uptime',
51 7 => 'Uptime_sec',
52 8 => 'Memmax_MB',
53 9 => 'Ulimit-n',
54 10 => 'Maxsock',
55 11 => 'Maxconn',
56 12 => 'CurrConns',
57);
58
59sub find_next_stat_id {
60 my($type, $field, $proxyid, $sid) = @_;
61
62 my $obj = 1 << $type;
63
64 my $np = -1;
65 my $nl = -1;
66
67 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
68 next if !$sock;
69
70 print $sock "show stat -1 $obj -1\n";
71
72 while(<$sock>) {
73 chomp;
74 my @d = split(',');
75
76 last if !$d[$field] && $field != FIELD_INDEX && $field != FIELD_NAME && /^#/;
77 next if /^#/;
78
79 next if $d[STATS_TYPE] != $type;
80
81 next if ($d[STATS_IID] < $proxyid) || ($d[STATS_IID] == $proxyid && $d[STATS_SID] <= $sid);
82
83 if ($np == -1 || $d[STATS_IID] < $np || ($d[STATS_IID] == $np && $d[STATS_SID] < $nl)) {
84 $np = $d[STATS_IID];
85 $nl = $d[STATS_SID];
86 next;
87 }
88 }
89
90 close($sock);
91
92 return 0 if ($np == -1);
93
94 return "$type.$field.$np.$nl"
95}
96
97sub haproxy_stat {
98 my($handler, $registration_info, $request_info, $requests) = @_;
99
100 for(my $request = $requests; $request; $request = $request->next()) {
101 my $oid = $request->getOID();
102
103 $oid =~ s/$oid_stat//;
104 $oid =~ s/^\.//;
105
106 my $mode = $request_info->getMode();
107
108 my($type, $field, $proxyid, $sid, $or) = split('\.', $oid, 5);
109
110 next if $type > 2 || defined($or);
111
112 if ($mode == MODE_GETNEXT) {
113
114 $type = 0 if !$type;
115 $field = 0 if !$field;
116 $proxyid = 0 if !$proxyid;
117 $sid = 0 if !$sid;
118
119 my $nextid = find_next_stat_id($type, $field, $proxyid, $sid);
120 $nextid = find_next_stat_id($type, $field+1, 0, 0) if !$nextid;
121 $nextid = find_next_stat_id($type+1, 0, 0, 0) if !$nextid;
122
123 if ($nextid) {
124 ($type, $field, $proxyid, $sid) = split('\.', $nextid);
125 $request->setOID(sprintf("%s.%s", OID_HAPROXY_STATS, $nextid));
126 $mode = MODE_GET;
127 }
128 }
129
130 if ($mode == MODE_GET) {
131 next if !defined($proxyid) || !defined($type) || !defined($sid) || !defined($field);
132
133 my $obj = 1 << $type;
134
135 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
136 next if !$sock;
137
138 print $sock "show stat $proxyid $obj $sid\n";
139
140 while(<$sock>) {
141 chomp;
142 my @data = split(',');
143
144 last if !defined($data[$field]) && $field != FIELD_INDEX && $field != FIELD_NAME;
145
146 if ($proxyid) {
147 next if $data[STATS_IID] ne $proxyid;
148 next if $data[STATS_SID] ne $sid;
149 next if $data[STATS_TYPE] ne $type;
150 }
151
152 if ($field == FIELD_INDEX) {
153 $request->setValue(ASN_OCTET_STR,
154 sprintf("%s.%s", $data[STATS_IID],
155 $data[STATS_SID]));
156 } elsif ($field == FIELD_NAME) {
157 $request->setValue(ASN_OCTET_STR,
158 sprintf("%s/%s", $data[STATS_PXNAME],
159 $data[STATS_SVNAME]));
160 } else {
161 $request->setValue(ASN_OCTET_STR, $data[$field]);
162 }
163
164 close($sock);
165 last;
166 }
167
168 close($sock);
169 next;
170 }
171
172 }
173}
174
175sub haproxy_info {
176 my($handler, $registration_info, $request_info, $requests) = @_;
177
178 for(my $request = $requests; $request; $request = $request->next()) {
179 my $oid = $request->getOID();
180
181 $oid =~ s/$oid_info//;
182 $oid =~ s/^\.//;
183
184 my $mode = $request_info->getMode();
185
186 my($req, $nr, $or) = split('\.', $oid, 3);
187
188 next if $req >= 2 || defined($or);
189
190 if ($mode == MODE_GETNEXT) {
191 $req = 0 if !defined($req);
192 $nr = -1 if !defined($nr);
193
194 if (!defined($info_vars{$nr+1})) {
195 $req++;
196 $nr = -1;
197 }
198
199 next if $req >= 2;
200
201 $request->setOID(sprintf("%s.%s.%s", OID_HAPROXY_INFO, $req, ++$nr));
202 $mode = MODE_GET;
203
204 }
205
206 if ($mode == MODE_GET) {
207
208 next if !defined($req) || !defined($nr);
209
210 if ($req == 0) {
211 next if !defined($info_vars{$nr});
212 $request->setValue(ASN_OCTET_STR, $info_vars{$nr});
213 next;
214 }
215
216 if ($req == 1) {
217 next if !defined($info_vars{$nr});
218
219 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
220 next if !$sock;
221
222 print $sock "show info\n";
223
224 while(<$sock>) {
225 chomp;
226 my ($key, $val) = /(.*):\s*(.*)/;
227
228 next if $info_vars{$nr} ne $key;
229
230 $request->setValue(ASN_OCTET_STR, $val);
231 last;
232 }
233
234 close($sock);
235 }
236 }
237 }
238}
239
240$agent->register('Haproxy stat', OID_HAPROXY_STATS, \&haproxy_stat);
241$agent->register('Haproxy info', OID_HAPROXY_INFO, \&haproxy_info);
242