Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 1 | # |
Willy Tarreau | 6613a3d | 2021-05-09 06:41:37 +0200 | [diff] [blame] | 2 | # Net-SNMP perl plugin for HAProxy |
Krzysztof Piotr Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 3 | # Version 0.30 |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 4 | # |
Krzysztof Piotr Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 5 | # Copyright 2007-2010 Krzysztof Piotr Oledzki <ole@ans.pl> |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 6 | # |
Krzysztof Piotr Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 7 | # 1. get a variable from "show stat": |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 8 | # 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid |
Krzysztof Piotr Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 9 | # type: 0->frontend, 1->backend, 2->server, 3->socket |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 10 | # |
Krzysztof Piotr Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 11 | # 2. get a variable from "show info": |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 12 | # 1.3.6.1.4.1.29385.106.2.$req.$varnr |
| 13 | # |
| 14 | # TODO: |
| 15 | # - implement read timeout |
| 16 | # |
| 17 | |
| 18 | use NetSNMP::agent (':all'); |
| 19 | use NetSNMP::ASN qw(:all); |
| 20 | use IO::Socket::UNIX; |
| 21 | |
| 22 | use strict; |
| 23 | |
Willy Tarreau | 6613a3d | 2021-05-09 06:41:37 +0200 | [diff] [blame] | 24 | my $agent = new NetSNMP::agent('Name' => 'HAProxy'); |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 25 | my $sa = "/var/run/haproxy.stat"; |
| 26 | |
| 27 | use constant OID_HAPROXY => '1.3.6.1.4.1.29385.106'; |
| 28 | use constant OID_HAPROXY_STATS => OID_HAPROXY . '.1'; |
| 29 | use constant OID_HAPROXY_INFO => OID_HAPROXY . '.2'; |
| 30 | |
| 31 | my $oid_stat = new NetSNMP::OID(OID_HAPROXY_STATS); |
| 32 | my $oid_info = new NetSNMP::OID(OID_HAPROXY_INFO); |
| 33 | |
| 34 | use constant STATS_PXNAME => 0; |
| 35 | use constant STATS_SVNAME => 1; |
| 36 | use constant STATS_IID => 27; |
| 37 | use constant STATS_SID => 28; |
| 38 | use constant STATS_TYPE => 32; |
| 39 | |
| 40 | use constant FIELD_INDEX => 10001; |
| 41 | use constant FIELD_NAME => 10002; |
| 42 | |
| 43 | my %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 Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 56 | 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 Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 64 | ); |
| 65 | |
| 66 | sub 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 | |
| 104 | sub 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 Oledzki | 3989c4b | 2010-10-25 16:04:17 +0200 | [diff] [blame] | 117 | next if $type > 3 || defined($or); |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 118 | |
| 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 | |
| 182 | sub 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 Tarreau | 6613a3d | 2021-05-09 06:41:37 +0200 | [diff] [blame] | 247 | $agent->register('HAProxy stat', OID_HAPROXY_STATS, \&haproxy_stat); |
| 248 | $agent->register('HAProxy info', OID_HAPROXY_INFO, \&haproxy_info); |
Krzysztof Piotr Oledzki | 2c6962c | 2008-03-02 02:42:14 +0100 | [diff] [blame] | 249 | |