| 1 |
#!/usr/bin/perl -w |
|---|
| 2 |
# |
|---|
| 3 |
# Copyright (C) Rune Nordbøe Skillingstad - rune.skillingstad@ntnu.no |
|---|
| 4 |
# |
|---|
| 5 |
# This program is free software; you can redistribute it and/or |
|---|
| 6 |
# modify it under the terms of the GNU General Public License |
|---|
| 7 |
# as published by the Free Software Foundation; version 2 dated June, |
|---|
| 8 |
# 1991. |
|---|
| 9 |
# |
|---|
| 10 |
# This program is distributed in the hope that it will be useful, |
|---|
| 11 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 |
# GNU General Public License for more details. |
|---|
| 14 |
# |
|---|
| 15 |
# You should have received a copy of the GNU General Public License |
|---|
| 16 |
# along with this program; if not, write to the Free Software |
|---|
| 17 |
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 |
# |
|---|
| 19 |
# |
|---|
| 20 |
# $Log$ |
|---|
| 21 |
# |
|---|
| 22 |
#%# family=auto |
|---|
| 23 |
#%# capabilities=autoconf suggest |
|---|
| 24 |
|
|---|
| 25 |
use strict; |
|---|
| 26 |
|
|---|
| 27 |
my @ret = (); |
|---|
| 28 |
|
|---|
| 29 |
if(!eval "require VMware::Control::Server;") { |
|---|
| 30 |
push(@ret, "VMware::Control::Server not found"); |
|---|
| 31 |
} |
|---|
| 32 |
if(!eval "require VMware::Control::VM;") { |
|---|
| 33 |
push(@ret, "VMware::Control::VM not found"); |
|---|
| 34 |
} |
|---|
| 35 |
|
|---|
| 36 |
my $host = $ENV{'host'} || undef; |
|---|
| 37 |
my $port = $ENV{'port'} || 902; |
|---|
| 38 |
my $user = $ENV{'user'} || undef; |
|---|
| 39 |
my $passwd = $ENV{'passwd'} || undef; |
|---|
| 40 |
my $debug = $ENV{'debug'} || undef; |
|---|
| 41 |
|
|---|
| 42 |
my $server = undef;; |
|---|
| 43 |
my %result; |
|---|
| 44 |
my %names; |
|---|
| 45 |
|
|---|
| 46 |
if($ARGV[0] and $ARGV[0] eq "autoconf") { |
|---|
| 47 |
if(@ret) { |
|---|
| 48 |
print "no (" . join(", ", @ret) . ")\n"; |
|---|
| 49 |
exit(1); |
|---|
| 50 |
} |
|---|
| 51 |
my $ret = &connect(1); |
|---|
| 52 |
if($ret) { |
|---|
| 53 |
print "no ($ret)\n"; |
|---|
| 54 |
exit(1); |
|---|
| 55 |
} |
|---|
| 56 |
print "yes\n"; |
|---|
| 57 |
exit(0); |
|---|
| 58 |
} |
|---|
| 59 |
|
|---|
| 60 |
if($ARGV[0] and $ARGV[0] eq "suggest") { |
|---|
| 61 |
print join("\n", qw(disk net memory)) . "\n"; |
|---|
| 62 |
exit(0); |
|---|
| 63 |
} |
|---|
| 64 |
|
|---|
| 65 |
&connect(); |
|---|
| 66 |
&enumerate(); |
|---|
| 67 |
|
|---|
| 68 |
if($debug) { |
|---|
| 69 |
use Data::Dumper; |
|---|
| 70 |
print Dumper(%result); |
|---|
| 71 |
} |
|---|
| 72 |
|
|---|
| 73 |
my $type = $0; |
|---|
| 74 |
$type =~ s/.*_([^\W\d_]+)$/$1/; |
|---|
| 75 |
|
|---|
| 76 |
if($ARGV[0] and $ARGV[0] eq "config") { |
|---|
| 77 |
if($type eq "net") { |
|---|
| 78 |
&config_net(); |
|---|
| 79 |
} elsif($type eq "disk") { |
|---|
| 80 |
&config_disk(); |
|---|
| 81 |
} elsif($type eq "memory") { |
|---|
| 82 |
&config_memory(); |
|---|
| 83 |
} else { |
|---|
| 84 |
exit(2); |
|---|
| 85 |
} |
|---|
| 86 |
} |
|---|
| 87 |
|
|---|
| 88 |
if($type eq "net") { |
|---|
| 89 |
&fetch_net(); |
|---|
| 90 |
} elsif($type eq "disk") { |
|---|
| 91 |
&fetch_disk(); |
|---|
| 92 |
} elsif($type eq "memory") { |
|---|
| 93 |
&fetch_memory(); |
|---|
| 94 |
} else { |
|---|
| 95 |
exit(2); |
|---|
| 96 |
} |
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
## ================================================================== |
|---|
| 100 |
|
|---|
| 101 |
&connect(); |
|---|
| 102 |
|
|---|
| 103 |
sub fetch_cpu { |
|---|
| 104 |
foreach my $host (sort(keys(%result))) { |
|---|
| 105 |
print &rrd_name($host) . ".value " . |
|---|
| 106 |
$result{$host}{vm}{cpuusage} . "\n"; |
|---|
| 107 |
} |
|---|
| 108 |
} |
|---|
| 109 |
|
|---|
| 110 |
sub fetch_memory { |
|---|
| 111 |
foreach my $host (sort(keys(%result))) { |
|---|
| 112 |
if(defined $result{$host}{vm}{ram}) { |
|---|
| 113 |
print &rrd_name($host) . "_used.value " . |
|---|
| 114 |
$result{$host}{vm}{ram} . "\n"; |
|---|
| 115 |
print &rrd_name($host) . "_free.value " . |
|---|
| 116 |
(($result{$host}{config}{memsize} * 1048576) - $result{$host}{vm}{ram}) . "\n"; |
|---|
| 117 |
} |
|---|
| 118 |
} |
|---|
| 119 |
} |
|---|
| 120 |
|
|---|
| 121 |
sub fetch_net { |
|---|
| 122 |
foreach my $host (sort(keys(%result))) { |
|---|
| 123 |
foreach my $dev (grep(/ethernet\d+/, sort(keys(%{$result{$host}})))) { |
|---|
| 124 |
print &rrd_name($host."_".$dev) . "_in.value " . $result{$host}{$dev}{bytesread} . "\n"; |
|---|
| 125 |
print &rrd_name($host."_".$dev) . "_out.value " . $result{$host}{$dev}{byteswritten} . "\n"; |
|---|
| 126 |
} |
|---|
| 127 |
} |
|---|
| 128 |
} |
|---|
| 129 |
|
|---|
| 130 |
sub fetch_disk { |
|---|
| 131 |
foreach my $host (sort(keys(%result))) { |
|---|
| 132 |
foreach my $dev (grep(/(?:scsi|ide)\d+:\d/, sort(keys(%{$result{$host}})))) { |
|---|
| 133 |
print &rrd_name($host."_".$dev) . "_read.value " . $result{$host}{$dev}{bytesread} . "\n"; |
|---|
| 134 |
print &rrd_name($host."_".$dev) . "_write.value " . $result{$host}{$dev}{byteswritten} . "\n"; |
|---|
| 135 |
} |
|---|
| 136 |
} |
|---|
| 137 |
} |
|---|
| 138 |
|
|---|
| 139 |
sub config_cpu { |
|---|
| 140 |
print "graph_args --base 1000 -r --lower-limit 0\n"; # --upper-limit 100\n"; |
|---|
| 141 |
print "graph_title CPU usage pr VM\n"; |
|---|
| 142 |
print "graph_scale no\n"; |
|---|
| 143 |
print "graph_category vmware\n"; |
|---|
| 144 |
print "graph_info This graph shows CPU usage pr VM\n"; |
|---|
| 145 |
print "graph_order " . join(" ", map{&rrd_name($_)}sort(keys(%result))) . "\n"; |
|---|
| 146 |
|
|---|
| 147 |
my $first = 1; |
|---|
| 148 |
foreach $host (sort(keys(%result))) { |
|---|
| 149 |
if($first) { |
|---|
| 150 |
print &rrd_name($host) . ".draw AREA\n"; |
|---|
| 151 |
$first = 0; |
|---|
| 152 |
} else { |
|---|
| 153 |
print &rrd_name($host) . ".draw STACK\n"; |
|---|
| 154 |
} |
|---|
| 155 |
print &rrd_name($host) . ".min 0\n"; |
|---|
| 156 |
print &rrd_name($host) . ".max 100\n"; |
|---|
| 157 |
print &rrd_name($host) . ".label $host cpu\n"; |
|---|
| 158 |
print &rrd_name($host) . ".type DERIVE\n"; |
|---|
| 159 |
print &rrd_name($host) . ".info % CPU usage on $host\n"; |
|---|
| 160 |
} |
|---|
| 161 |
print "idle.min 0\n"; |
|---|
| 162 |
print "idle.max 100\n"; |
|---|
| 163 |
print "idle.label idle cpu\n"; |
|---|
| 164 |
print "idle.type DERIVE\n"; |
|---|
| 165 |
print "idle.draw STACK\n"; |
|---|
| 166 |
print "idle.info % idle CPU usage \n"; |
|---|
| 167 |
print "idle.cdef 100," . join(",-,", map{&rrd_name($_);}keys(%result)) . ",-\n"; |
|---|
| 168 |
exit(0); |
|---|
| 169 |
} |
|---|
| 170 |
|
|---|
| 171 |
sub config_memory { |
|---|
| 172 |
my $total = 0; |
|---|
| 173 |
foreach my $host (keys(%result)) { |
|---|
| 174 |
if(defined $result{$host}{vm}{ram}) { |
|---|
| 175 |
$total += ($result{$host}{config}{memsize} * 1048576); |
|---|
| 176 |
} |
|---|
| 177 |
} |
|---|
| 178 |
print "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit $total\n"; |
|---|
| 179 |
print "graph_title Memory usage pr VM\n"; |
|---|
| 180 |
print "graph_category vmware\n"; |
|---|
| 181 |
print "graph_info This graph shows memory usage and limits pr VM\n"; |
|---|
| 182 |
print "graph_total Total\n"; |
|---|
| 183 |
|
|---|
| 184 |
print "graph_order "; |
|---|
| 185 |
foreach my $host (sort(keys(%result))) { |
|---|
| 186 |
if(defined $result{$host}{vm}{ram}) { |
|---|
| 187 |
print &rrd_name($host) . "_used " . &rrd_name($host) . "_free "; |
|---|
| 188 |
} |
|---|
| 189 |
} |
|---|
| 190 |
print "\n"; |
|---|
| 191 |
|
|---|
| 192 |
my $first = 1; |
|---|
| 193 |
foreach $host (sort(keys(%result))) { |
|---|
| 194 |
if(defined $result{$host}{vm}{ram}) { |
|---|
| 195 |
if($first) { |
|---|
| 196 |
print &rrd_name($host) . "_used.draw AREA\n"; |
|---|
| 197 |
$first = 0; |
|---|
| 198 |
} else { |
|---|
| 199 |
print &rrd_name($host) . "_used.draw STACK\n"; |
|---|
| 200 |
} |
|---|
| 201 |
print &rrd_name($host) . "_used.min 0\n"; |
|---|
| 202 |
print &rrd_name($host) . "_used.label $host used\n"; |
|---|
| 203 |
print &rrd_name($host) . "_used.info Used memory on $host\n"; |
|---|
| 204 |
print &rrd_name($host) . "_free.draw STACK\n"; |
|---|
| 205 |
print &rrd_name($host) . "_free.min 0\n"; |
|---|
| 206 |
print &rrd_name($host) . "_free.label $host free\n"; |
|---|
| 207 |
print &rrd_name($host) . "_free.info Free memory on $host\n"; |
|---|
| 208 |
} |
|---|
| 209 |
} |
|---|
| 210 |
exit(0); |
|---|
| 211 |
} |
|---|
| 212 |
|
|---|
| 213 |
sub config_net { |
|---|
| 214 |
print "graph_args --base 1000\n"; |
|---|
| 215 |
print "graph_vlabel read (-) / written (+)\n"; |
|---|
| 216 |
print "graph_title Traffic usage pr VM\n"; |
|---|
| 217 |
print "graph_category vmware\n"; |
|---|
| 218 |
print "graph_info This graph shows the network traffic pr VM\n"; |
|---|
| 219 |
|
|---|
| 220 |
print "graph_order "; |
|---|
| 221 |
foreach my $host (sort(keys(%result))) { |
|---|
| 222 |
foreach my $dev (grep(/ethernet\d+/, sort(keys(%{$result{$host}})))) { |
|---|
| 223 |
print &rrd_name($host."_".$dev) . "_in " . &rrd_name($host."_".$dev) . "_out "; |
|---|
| 224 |
} |
|---|
| 225 |
} |
|---|
| 226 |
print "\n"; |
|---|
| 227 |
|
|---|
| 228 |
foreach $host (sort(keys(%result))) { |
|---|
| 229 |
foreach my $dev (grep(/ethernet\d+/, sort(keys(%{$result{$host}})))) { |
|---|
| 230 |
print &rrd_name($host."_".$dev) . "_in.label $host $dev\n"; |
|---|
| 231 |
print &rrd_name($host."_".$dev) . "_in.type DERIVE\n"; |
|---|
| 232 |
print &rrd_name($host."_".$dev) . "_in.max 900000\n"; |
|---|
| 233 |
print &rrd_name($host."_".$dev) . "_in.min 0\n"; |
|---|
| 234 |
print &rrd_name($host."_".$dev) . "_in.graph no\n"; |
|---|
| 235 |
print &rrd_name($host."_".$dev) . "_out.label $host $dev\n"; |
|---|
| 236 |
print &rrd_name($host."_".$dev) . "_out.info Traffic on device $dev for host $host\n"; |
|---|
| 237 |
print &rrd_name($host."_".$dev) . "_out.type DERIVE\n"; |
|---|
| 238 |
print &rrd_name($host."_".$dev) . "_out.max 900000\n"; |
|---|
| 239 |
print &rrd_name($host."_".$dev) . "_out.min 0\n"; |
|---|
| 240 |
print &rrd_name($host."_".$dev) . "_out.negative " . &rrd_name($host."_".$dev) . "_in\n"; |
|---|
| 241 |
} |
|---|
| 242 |
} |
|---|
| 243 |
exit(0); |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|
| 246 |
sub config_disk { |
|---|
| 247 |
print "graph_args --base 1024 -l 0\n"; |
|---|
| 248 |
print "graph_vlabel read (-) / written (+)\n"; |
|---|
| 249 |
print "graph_title IOstat usage pr VM\n"; |
|---|
| 250 |
print "graph_category vmware\n"; |
|---|
| 251 |
print "graph_info This graph shows the I/O to and from block devices pr VM\n"; |
|---|
| 252 |
|
|---|
| 253 |
print "graph_order "; |
|---|
| 254 |
foreach my $host (sort(keys(%result))) { |
|---|
| 255 |
foreach my $dev (grep(/(?:scsi|ide)\d+:\d/, sort(keys(%{$result{$host}})))) { |
|---|
| 256 |
print &rrd_name($host."_".$dev) . "_read " . &rrd_name($host."_".$dev) . "_write "; |
|---|
| 257 |
} |
|---|
| 258 |
} |
|---|
| 259 |
print "\n"; |
|---|
| 260 |
|
|---|
| 261 |
foreach $host (sort(keys(%result))) { |
|---|
| 262 |
foreach my $dev (grep(/(?:scsi|ide)\d+:\d/, sort(keys(%{$result{$host}})))) { |
|---|
| 263 |
print &rrd_name($host."_".$dev) . "_read.label $host $dev\n"; |
|---|
| 264 |
print &rrd_name($host."_".$dev) . "_read.type DERIVE\n"; |
|---|
| 265 |
print &rrd_name($host."_".$dev) . "_read.max 900000\n"; |
|---|
| 266 |
print &rrd_name($host."_".$dev) . "_read.min 0\n"; |
|---|
| 267 |
print &rrd_name($host."_".$dev) . "_read.graph no\n"; |
|---|
| 268 |
print &rrd_name($host."_".$dev) . "_write.label $host $dev\n"; |
|---|
| 269 |
print &rrd_name($host."_".$dev) . "_write.info I/O on device $dev for host $host\n"; |
|---|
| 270 |
print &rrd_name($host."_".$dev) . "_write.type DERIVE\n"; |
|---|
| 271 |
print &rrd_name($host."_".$dev) . "_write.max 900000\n"; |
|---|
| 272 |
print &rrd_name($host."_".$dev) . "_write.min 0\n"; |
|---|
| 273 |
print &rrd_name($host."_".$dev) . "_write.negative " . &rrd_name($host."_".$dev) . "_read\n"; |
|---|
| 274 |
} |
|---|
| 275 |
} |
|---|
| 276 |
exit(0); |
|---|
| 277 |
} |
|---|
| 278 |
|
|---|
| 279 |
sub rrd_name { |
|---|
| 280 |
my $name = shift; |
|---|
| 281 |
if(!defined $names{$name}) { |
|---|
| 282 |
print "rrd_name on $name running\n" if $debug; |
|---|
| 283 |
my $new = lc($name); |
|---|
| 284 |
$new =~ s/\s/_/g; |
|---|
| 285 |
$new =~ s/:/_/g; |
|---|
| 286 |
$names{$name} = $new; |
|---|
| 287 |
} |
|---|
| 288 |
return $names{$name}; |
|---|
| 289 |
} |
|---|
| 290 |
|
|---|
| 291 |
sub enumerate { |
|---|
| 292 |
my @hosts = $server->enumerate(); |
|---|
| 293 |
|
|---|
| 294 |
if(!@hosts) { |
|---|
| 295 |
my ($errno, $errstr) = $server->get_last_error(); |
|---|
| 296 |
die "Could not get list of VMs from server: Error $errno: $errstr\n"; |
|---|
| 297 |
} |
|---|
| 298 |
|
|---|
| 299 |
foreach my $host (@hosts) { |
|---|
| 300 |
&check_host($host); |
|---|
| 301 |
} |
|---|
| 302 |
} |
|---|
| 303 |
|
|---|
| 304 |
sub connect { |
|---|
| 305 |
my $test = shift; |
|---|
| 306 |
if($server) { |
|---|
| 307 |
return $server; |
|---|
| 308 |
} |
|---|
| 309 |
$server = VMware::Control::Server::new($host, $port, $user, $passwd); |
|---|
| 310 |
if(!$server->connect()) { |
|---|
| 311 |
my ($errno, $errstr) = $server->get_last_error(); |
|---|
| 312 |
$server = undef; |
|---|
| 313 |
if(!$test) { |
|---|
| 314 |
die "Could not connect to server: Error $errno: $errstr\n"; |
|---|
| 315 |
} else { |
|---|
| 316 |
return "$errno: $errstr"; |
|---|
| 317 |
} |
|---|
| 318 |
} |
|---|
| 319 |
if($test) { |
|---|
| 320 |
my $conf = ($server->enumerate())[0]; |
|---|
| 321 |
my $vm = VMware::Control::VM::new($server, $conf); |
|---|
| 322 |
if(!$vm->connect()) { |
|---|
| 323 |
my ($errno, $errstr) = $server->get_last_error(); |
|---|
| 324 |
return "Could not check version"; |
|---|
| 325 |
} |
|---|
| 326 |
my $vers = $vm->get("Status.version"); |
|---|
| 327 |
print "Checking \"$vers\" for GSX" if $debug; |
|---|
| 328 |
if($vers !~ /GSX/) { |
|---|
| 329 |
return "Not GSX"; |
|---|
| 330 |
} |
|---|
| 331 |
} |
|---|
| 332 |
|
|---|
| 333 |
print "Connected to server\n" if $debug; |
|---|
| 334 |
return 0; |
|---|
| 335 |
} |
|---|
| 336 |
|
|---|
| 337 |
|
|---|
| 338 |
|
|---|
| 339 |
sub check_host { |
|---|
| 340 |
$host = shift; |
|---|
| 341 |
print "Checking $host\n" if $debug; |
|---|
| 342 |
my $vm = VMware::Control::VM::new($server, $host); |
|---|
| 343 |
if(!$vm->connect()) { |
|---|
| 344 |
my ($errno, $errstr) = $server->get_last_error(); |
|---|
| 345 |
warn "Could not connect to server: Error $errno: $errstr\n"; |
|---|
| 346 |
} |
|---|
| 347 |
|
|---|
| 348 |
if($vm->get("Status.power") eq "on") { |
|---|
| 349 |
my $name = $vm->get("Config.displayName"); |
|---|
| 350 |
print "Host $name is on\n" if $debug; |
|---|
| 351 |
my $mem = $vm->get("Config.memsize"); |
|---|
| 352 |
$result{$name}{"config"}{"memsize"} = $mem; |
|---|
| 353 |
my $devs = ($vm->get("Status.stats.devices")); |
|---|
| 354 |
print "Found devices: " . join(" ", @{$devs}) . "\n" if $debug; |
|---|
| 355 |
foreach my $dev (@{$devs}) { |
|---|
| 356 |
my $stats = $vm->get("Status.stats.$dev.stats"); |
|---|
| 357 |
if(!$stats) { |
|---|
| 358 |
next; |
|---|
| 359 |
} |
|---|
| 360 |
print "Found status for $dev: " . join(" ", @{$stats}) . "\n" if $debug; |
|---|
| 361 |
for my $stat (@{$stats}) { |
|---|
| 362 |
my $val = $vm->get("Status.stats.$dev.$stat"); |
|---|
| 363 |
$result{$name}{$dev}{$stat} = $val; |
|---|
| 364 |
print "Got value for $stat on $dev: $val\n" if $debug; |
|---|
| 365 |
} |
|---|
| 366 |
} |
|---|
| 367 |
} |
|---|
| 368 |
$vm->disconnect(); |
|---|
| 369 |
} |
|---|
| 370 |
|
|---|
| 371 |
undef $server; |
|---|