1#!@@PERL@@ 2# 3# Plugin to monitor connections per second, for LVS loadbalancers. 4# 5# Wildcard names: 6# 7# cps_<port> 8# cps_<vip>_<port> 9# 10# Examples: 11# 12# cps_smtp 13# cps_mail.foo.boo_smtp 14# cps_pop3 15# cps_www.foo.boo_www 16# cps_vvv.foo.boo_www 17# 18# Parameters understood: 19# 20# config (required) 21# autoconf (optional - used by munin-config) 22# suggest (optional - used by munin-config) 23# 24# Magic markers - optional - used by installation scripts and munin-config: 25# 26#%# family=auto 27#%# capabilities=autoconf suggest 28# 29 30use warnings; 31use strict; 32 33if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) { 34 autoconf (); 35} 36 37if ( defined $ARGV[0] and $ARGV[0] eq "suggest" ) { 38 my $sipvs; 39 $sipvs = &ipvs (".", ".", $sipvs); 40 exit 0 if $sipvs == undef; 41 suggest ($sipvs); 42} 43 44unless ($0 =~ /cps(?:_([^_]+)|)_(.+)\s*$/) { 45 die "Could not parse name $0.\n"; 46} 47 48my $vip = $1; 49my $port = $2; 50my $ipvs; 51 52#print "$vip:$port\n"; 53 54use Socket; 55my $name; 56my $address; 57$address = inet_aton($vip); 58$name = gethostbyaddr($address,AF_INET); 59 60#print "$vip:$port\n"; 61#print "Name: $0\nPort: $port\nVip : $vip\n"; 62 63# Read ipvsadm-output 64 65$ipvs = &ipvs ($vip, $port, $ipvs); 66 67if ( defined $ARGV[0] and $ARGV[0] eq "config" ) { 68 config ($vip, $port, $ipvs); 69} 70 71$vip = $vip || ""; 72if (exists ($ipvs->{$vip}) and exists ($ipvs->{$vip}->{$port})) { 73 foreach my $host (sort keys %{$ipvs->{$vip}->{$port}}) { 74 (my $fname = $host) =~ s/[.-]/_/g; 75 print "$fname.value ", $ipvs->{$vip}->{$port}->{$host}, "\n";; 76 } 77} 78 79 80sub autoconf { 81 system ("/sbin/ipvsadm -L -n --stats >/dev/null 2>/dev/null"); 82 83 if ($? == 0) { 84 print "yes\n"; 85 exit 0; 86 } 87 elsif ($? & 127) { 88 print "no (system call exited with %d)", $? & 127; 89 } 90 elsif (($?>>8) == 2) { 91 print "no (permission denied)\n"; 92 exit 0; 93 } 94 elsif (($?>>8) == 127) { 95 print "no (ipvsadm not found)\n"; 96 exit 0; 97 } else { 98 print "no (unknown ipvsadm return value: $?, %d)\n", $? >> 8; 99 exit 0; 100 } 101} 102 103 104sub suggest { 105 my $ipvs = shift; 106 exit 0 unless $ipvs; 107 108 foreach my $vip (sort keys %{$ipvs}) { 109 foreach my $port (sort keys %{$ipvs->{$vip}}) { 110 print "${vip}_$port\n"; 111 } 112 } 113 exit 0; 114} 115 116 117sub config { 118 my $vip = shift; 119 my $port = shift; 120 my $ipvs = shift; 121 122 print "graph_title Loadbalanced ",($name?$name:"*"),"->",$port," connections\n"; 123 print "graph_args -l 0\n"; 124 print "graph_total total\n"; 125 print "graph_vlabel connections / \${graph_period}\n"; 126 print "graph_category network\n"; 127 my $first=1; 128 $vip = $vip || ""; 129 if (exists ($ipvs->{$vip}) and exists ($ipvs->{$vip}->{$port})) { 130 foreach my $host (sort keys %{$ipvs->{$vip}->{$port}}) { 131 (my $fname = $host) =~ s/[.-]/_/g; 132 if ( $first == 1 ) { 133 print "$fname.draw AREA\n"; 134 $first=0 135 } else { 136 print "$fname.draw STACK\n"; 137 } 138 print "$fname.type DERIVE\n"; 139 $host =~ s/-bak//; 140 print "$fname.label $host\n"; 141 print "$fname.max 1000\n"; 142 print "$fname.min 0\n"; 143 } 144 } 145 exit 0; 146} 147 148sub ipvs { 149 my $vip = shift; 150 my $port = shift; 151 my $ipvs = shift; 152 open (IPVS, "/sbin/ipvsadm -L -n --stats 2>/dev/null|") or return undef; 153 my $cvip = ""; 154 my $cport = ""; 155 while (<IPVS>) { 156 next if /^IP Virtual Server/; 157 next if /^Prot\s+LocalAddress/; 158 if (/^(\w+)\s+([\w\.-]+):([\w\d]+)\s+(\d+)[KMG]?\s+/) { 159 $cvip = ($vip?$2:""); 160 $cport = $3; 161 } 162 elsif (/^\s+->\s+([^:]+):(\S+)\s+(\d+)G\s+/) { 163 $ipvs->{$cvip}->{$cport}->{$1} += ($3*1000000000); 164 } 165 elsif (/^\s+->\s+([^:]+):(\S+)\s+(\d+)M\s+/) { 166 $ipvs->{$cvip}->{$cport}->{$1} += ($3*1000000); 167 } 168 elsif (/^\s+->\s+([^:]+):(\S+)\s+(\d+)K\s+/) { 169 $ipvs->{$cvip}->{$cport}->{$1} += ($3*1000); 170 } 171 elsif (/^\s+->\s+([^:]+):(\S+)\s+(\d+)\s+/) { 172 $ipvs->{$cvip}->{$cport}->{$1} += $3; 173 } 174 } 175 close (IPVS) or return undef; 176 return $ipvs; 177} 178# vim:syntax=perl 179