blob: 64684ad01838590cf624b8295001135051d26786 [file] [log] [blame]
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001#
Willy Tarreau6613a3d2021-05-09 06:41:37 +02002# Net-SNMP perl plugin for HAProxy
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +02003# Version 0.30
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01004#
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +02005# Copyright 2007-2010 Krzysztof Piotr Oledzki <ole@ans.pl>
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01006#
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +02007# 1. get a variable from "show stat":
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01008# 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +02009# type: 0->frontend, 1->backend, 2->server, 3->socket
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +010010#
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +020011# 2. get a variable from "show info":
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +010012# 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
Willy Tarreau6613a3d2021-05-09 06:41:37 +020024my $agent = new NetSNMP::agent('Name' => 'HAProxy');
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +010025my $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',
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +020056 12 => 'Maxpipes',
57 13 => 'CurrConns',
58 14 => 'PipesUsed',
59 15 => 'PipesFree',
60 16 => 'Tasks',
61 17 => 'Run_queue',
62 18 => 'node',
63 19 => 'description',
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +010064);
65
66sub find_next_stat_id {
67 my($type, $field, $proxyid, $sid) = @_;
68
69 my $obj = 1 << $type;
70
71 my $np = -1;
72 my $nl = -1;
73
74 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
75 next if !$sock;
76
77 print $sock "show stat -1 $obj -1\n";
78
79 while(<$sock>) {
80 chomp;
81 my @d = split(',');
82
83 last if !$d[$field] && $field != FIELD_INDEX && $field != FIELD_NAME && /^#/;
84 next if /^#/;
85
86 next if $d[STATS_TYPE] != $type;
87
88 next if ($d[STATS_IID] < $proxyid) || ($d[STATS_IID] == $proxyid && $d[STATS_SID] <= $sid);
89
90 if ($np == -1 || $d[STATS_IID] < $np || ($d[STATS_IID] == $np && $d[STATS_SID] < $nl)) {
91 $np = $d[STATS_IID];
92 $nl = $d[STATS_SID];
93 next;
94 }
95 }
96
97 close($sock);
98
99 return 0 if ($np == -1);
100
101 return "$type.$field.$np.$nl"
102}
103
104sub haproxy_stat {
105 my($handler, $registration_info, $request_info, $requests) = @_;
106
107 for(my $request = $requests; $request; $request = $request->next()) {
108 my $oid = $request->getOID();
109
110 $oid =~ s/$oid_stat//;
111 $oid =~ s/^\.//;
112
113 my $mode = $request_info->getMode();
114
115 my($type, $field, $proxyid, $sid, $or) = split('\.', $oid, 5);
116
Krzysztof Piotr Oledzki3989c4b2010-10-25 16:04:17 +0200117 next if $type > 3 || defined($or);
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100118
119 if ($mode == MODE_GETNEXT) {
120
121 $type = 0 if !$type;
122 $field = 0 if !$field;
123 $proxyid = 0 if !$proxyid;
124 $sid = 0 if !$sid;
125
126 my $nextid = find_next_stat_id($type, $field, $proxyid, $sid);
127 $nextid = find_next_stat_id($type, $field+1, 0, 0) if !$nextid;
128 $nextid = find_next_stat_id($type+1, 0, 0, 0) if !$nextid;
129
130 if ($nextid) {
131 ($type, $field, $proxyid, $sid) = split('\.', $nextid);
132 $request->setOID(sprintf("%s.%s", OID_HAPROXY_STATS, $nextid));
133 $mode = MODE_GET;
134 }
135 }
136
137 if ($mode == MODE_GET) {
138 next if !defined($proxyid) || !defined($type) || !defined($sid) || !defined($field);
139
140 my $obj = 1 << $type;
141
142 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
143 next if !$sock;
144
145 print $sock "show stat $proxyid $obj $sid\n";
146
147 while(<$sock>) {
148 chomp;
149 my @data = split(',');
150
151 last if !defined($data[$field]) && $field != FIELD_INDEX && $field != FIELD_NAME;
152
153 if ($proxyid) {
154 next if $data[STATS_IID] ne $proxyid;
155 next if $data[STATS_SID] ne $sid;
156 next if $data[STATS_TYPE] ne $type;
157 }
158
159 if ($field == FIELD_INDEX) {
160 $request->setValue(ASN_OCTET_STR,
161 sprintf("%s.%s", $data[STATS_IID],
162 $data[STATS_SID]));
163 } elsif ($field == FIELD_NAME) {
164 $request->setValue(ASN_OCTET_STR,
165 sprintf("%s/%s", $data[STATS_PXNAME],
166 $data[STATS_SVNAME]));
167 } else {
168 $request->setValue(ASN_OCTET_STR, $data[$field]);
169 }
170
171 close($sock);
172 last;
173 }
174
175 close($sock);
176 next;
177 }
178
179 }
180}
181
182sub haproxy_info {
183 my($handler, $registration_info, $request_info, $requests) = @_;
184
185 for(my $request = $requests; $request; $request = $request->next()) {
186 my $oid = $request->getOID();
187
188 $oid =~ s/$oid_info//;
189 $oid =~ s/^\.//;
190
191 my $mode = $request_info->getMode();
192
193 my($req, $nr, $or) = split('\.', $oid, 3);
194
195 next if $req >= 2 || defined($or);
196
197 if ($mode == MODE_GETNEXT) {
198 $req = 0 if !defined($req);
199 $nr = -1 if !defined($nr);
200
201 if (!defined($info_vars{$nr+1})) {
202 $req++;
203 $nr = -1;
204 }
205
206 next if $req >= 2;
207
208 $request->setOID(sprintf("%s.%s.%s", OID_HAPROXY_INFO, $req, ++$nr));
209 $mode = MODE_GET;
210
211 }
212
213 if ($mode == MODE_GET) {
214
215 next if !defined($req) || !defined($nr);
216
217 if ($req == 0) {
218 next if !defined($info_vars{$nr});
219 $request->setValue(ASN_OCTET_STR, $info_vars{$nr});
220 next;
221 }
222
223 if ($req == 1) {
224 next if !defined($info_vars{$nr});
225
226 my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
227 next if !$sock;
228
229 print $sock "show info\n";
230
231 while(<$sock>) {
232 chomp;
233 my ($key, $val) = /(.*):\s*(.*)/;
234
235 next if $info_vars{$nr} ne $key;
236
237 $request->setValue(ASN_OCTET_STR, $val);
238 last;
239 }
240
241 close($sock);
242 }
243 }
244 }
245}
246
Willy Tarreau6613a3d2021-05-09 06:41:37 +0200247$agent->register('HAProxy stat', OID_HAPROXY_STATS, \&haproxy_stat);
248$agent->register('HAProxy info', OID_HAPROXY_INFO, \&haproxy_info);
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100249