Logoj0ke.net Open Build Service > Projects > server:monitoring > nagios-plugins-snmp > check_esx3
Sign Up | Log In

File check_esx3 of Package nagios-plugins-snmp

x
 
1
#!/usr/bin/perl -w
2
# vim:ts=4
3
# check_esx Version 3.0
4
#
5
# Check the status of a virtual machine on a VMware ESX server, via SNMP
6
# Return status in format for either Nagios or MRTG
7
#
8
# Steve Shipway (www.steveshipway.org) Nov 2004, Dec 2006, Aug 2007
9
# Released under GNU GPL
10
#
11
# Version 2.0: Added SNMP agent extension to get memory split and ready time
12
#         2.1: Corrected some bugs.  Use >0.01 instead of >0.
13
#         2.2: corrected opt_r bug, fa bug
14
#         2.3:
15
#         2.4: simpler guest names for list report
16
#         2.5: Thresholds for LIST given more sensible defaults
17
#              Added -a alternate for MRTG/Nagios in MEM and CPU
18
#         2.6: Final tests under ESX3
19
#         3.0: Merge in GW additions, change -v to -V to standardise
20
21
use Net::SNMP;
22
use Getopt::Std;
23
24
my($VERSION) = "3.0";
25
######## CONFIGURABLE
26
my($STATEFILE) = "/var/tmp/esx_state";    # For rate counter (if not agent)
27
my($SWAPINCRIT) = 1024; # this many bps swap in is critical (else warn)
28
my($SWAPINWARN) = 128; 
29
my($SWAPPCCRIT) = 4; # this % of gruest memory in swap is critical (else warn)
30
my($SWAPPCWARN) = 1; # under ESX3, this is always >0 by a tiny bit
31
my($warn,$crit) = (70,90);   # usage warn/crit: 70/90 is virtualcentre default
32
my($rwarn,$rcrit) = (10,15); # cpu readytime warn/crit: VMWare say to crit at 5%
33
my($community) = 'public'; # Default community string
34
my($TRUNC) = 16; # truncte guest names in report to this length (use 99 to stop)
35
######## END
36
my($VMOID) = "1.3.6.1.4.1.6876";          # VMware MIB
37
my($UCDOID) = "1.3.6.1.4.1.2021.1000.10"; # where to find the agent plugin
38
my($SYSOID) = "1.3.6.1.2.1.1.1.0";        # system object to test SNMP working
39
my($OK,$WARNING,$CRITICAL,$UNKNOWN) = (0,1,2,3);
40
my(%VisibleStatus) = ($OK => "OK", $WARNING => "WARNING", $CRITICAL => "CRITICAL", $UNKNOWN => "UNKNOWN");
41
my($TIMEOUT) = 5;
42
my($RETRIES) = 1;
43
my($from,$to) = (0,99999);
44
my(%snmp,$snmp,$resp,$snmperr);
45
my($hostname) = '';
46
my($vhost) = '';
47
my($A, $B, $MSG) = ('U','U','');
48
my($STATUS) = $UNKNOWN;
49
my($MODE) = 0;
50
my($VMID) = -1; # set to -1 if not running
51
my($VMNO) = -1; # set to -1 if not defined
52
my(%lookup) = ();
53
my(%states) = ();
54
my(%tmpnet) = ();
55
my($fa,$sa,$fb,$sb);
56
my(@perf) = (); # for performance stats
57
# For debugging
58
my($DEBUG) = 0;
59
my($SNMPFILE) = "testdata/snmp.txt"; # for test/debug mode only
60
my($VMWARESTATS) = "./vmware-stats -d"; # for test/debug mode only
61
# End
62
63
use vars qw($opt_C $opt_H $opt_N $opt_M $opt_h $opt_c $opt_t $opt_i $opt_d $opt_w $opt_l $opt_v $opt_r $opt_R $opt_a $opt_V);
64
65
sub base($) {
66
    return '?' if(!$_[0]);
67
    return $1 if( $_[0]=~/^(\S+)/ );
68
    return $_[0];
69
}
70
71
sub dohelp {
72
    print "Usage: $0 [-h] [-v] [-d] -H host [-C community] [-N | -M [-r]]\n";
73
    print "          [-l check [-V vhost] [-i interface] [-w warn -c crit]]\n";
74
    print "          [-t timeout] [-R retries]\n";
75
    print "    -h: just prints this help message\n";
76
    print "    -v: just prints the script version number\n";
77
    print "    -d: puts the script into debug mode\n";
78
    print "    -H host: ESX server machine\n";
79
    print "    -C community: the SNMP community string (default is \"public\")\n";
80
    print "    -N: Nagios mode (the default); need -w and -c for CPU, MEM\n";
81
    print "    -M: MRTG mode (-r specifies rate rather than counter)\n";
82
    print "    -l check: can be CPU MEM STATE LIST NET LISTNET (default is LIST)\n";
83
    print "    -V virtualhost: restrict probing to that one guest host; required for STATE;\n";
84
    print "        if not specified, probes total ESX system statistics\n";
85
    print "    -i interface: Only valid for NET\n";
86
    print "    -w warn -c crit: Nagios thresholds\n";
87
    print "    -t timeout: ([1..60] seconds) for individual SNMP queries\n";
88
    print "    -R retries: # of retries ([0..20]) for individual SNMP queries\n";
89
    print "\nFor MRTG,\n";
90
    print "    CPU is total seconds (counter) for vhost or total over all if no vhost given.\n";
91
    print "    MEM is memory remaining in K.\n";
92
    print "    STATE is 1 for up, 0 for down.\n";
93
    print "    LIST is number of vhosts.\n";
94
    print "    NET is network throughput in bytes for specified vhost and/or interface\n";
95
    print "        (total of all if not specified).\n";
96
    print "\nFor Nagios, specify thresholds as follows.\n";
97
    print "    CPU is percentage of allocated CPU (for vhosts) and of total CPU (if no vhost).\n";
98
    print "    MEM is active memory (for vhosts) or free phys memory (if no vhost) in K or %.\n";
99
    print "    STATE is CRITICAL if vhost is down.\n";
100
    print "    LIST is WARN if some are down, CRIT is all vhosts are down.\n";
101
    print "    NET is bytes/sec since last check, if possible (otherwise UNKNOWN).\n";
102
    print "\nThresholds for MEM or LIST under Nagios, can be in K or %\n";
103
    print "    e.g.: -l MEM -w 2048K -c 1024K\n";
104
    print "    e.g.: -l MEM -V vhost -w 80% -c 90%\n";
105
    print "    e.g.: -l LIST -w 90% -c 0\n";
106
    print "    e.g.: -l LIST -w 10 -c 1\n";
107
    print "Thresholds for CPU are in % (the trailing % symbol is optional)\n";
108
    print "    e.g.: -l CPU -w 80 -c 90\n";
109
    print "Thresholds for NET are in BYTES/SEC (cannot use %)\n";
110
    exit 0;
111
}
112
113
sub readstate {
114
    return if(! -r $STATEFILE);
115
    open STATE, "<$STATEFILE";
116
    flock STATE,1; # read lock
117
    while( <STATE> ) { $states{$1}=$2 if( /^(\S+)=(\d+)/ ); }
118
    flock STATE,8; # unlock
119
    close STATE;
120
}
121
122
# Big fixes for the race condition from GroundWork
123
sub writestate {
124
    my(%new) = @_;
125
126
    if(-r $STATEFILE) {
127
        open STATE, "+<$STATEFILE" 
128
            or do { $A=$B="U"; $MSG="$STATEFILE: $!"; $STATUS=3; &dooutput; };
129
        flock STATE,2; # write lock
130
        while( <STATE> ) { $states{$1}=$2 if( /^(\S+)=(\d+)/ ); }
131
    } else {
132
        open STATE, ">>$STATEFILE" 
133
            or do { $A=$B="U"; $MSG="$STATEFILE: $!"; $STATUS=3; &dooutput; };
134
        flock STATE,2; # write lock
135
136
    }
137
    seek STATE,0,0; # rewind
138
    truncate STATE,0;
139
    foreach ( keys %new ) { $states{$_} = $new{$_}; }
140
    foreach ( keys %states ) { print STATE "$_=".$states{$_}."\n"; }
141
    flock STATE,8; # unlock
142
    close STATE;
143
}
144
145
sub dooutput {
146
    if( $MODE ) {
147
        # MRTG
148
        $A = 'U' if(!defined $A);
149
        $B = $A if(!defined $B);
150
        $MSG = "Returned values: $A, $B\n" if(!$MSG);
151
        print "$A\n$B\n\n$MSG\n";
152
        exit 0;
153
    } else {
154
        # Nagios: now supporting performance stats
155
        print "".($VisibleStatus{$STATUS} || "UNKNOWN").": $MSG"
156
            .(scalar @perf ? "|" . join(" ",@perf) : ""), "\n";
157
        exit $STATUS;
158
    }
159
    # should never get here
160
}
161
162
sub snmpfile($) {
163
    my(%resp);
164
    my($k) = $_[0];
165
    foreach ( keys %snmp ) { $resp{$_} = $snmp{$_} if( /^$k\./); }
166
    return \%resp;
167
}
168
169
sub makesnmp() {
170
    if ($DEBUG and $SNMPFILE) {
171
        open SNMP,"<$SNMPFILE" or return;
172
        while(<SNMP>) { chomp; if(/^(\S+)\s+=\s+\S+:\s+"?([^"]+)/) { $snmp{$1}=$2; } }  
173
        close SNMP;
174
        return;
175
    }
176
    ($snmp,$snmperr) = Net::SNMP->session( -hostname=>$hostname,
177
        -community=>$community, -timeout=>$TIMEOUT, -retries=>$RETRIES );
178
    if($snmperr) {
179
        $A = $B = 'U';
180
        print "($snmperr)\n" if($DEBUG);
181
        $MSG = "Error: $snmperr";
182
        $STATUS = $UNKNOWN;
183
        dooutput; # exit 
184
        exit(0);
185
    }
186
}
187
188
###########################################################################
189
# Read detailed memory and CPU data from extended snmp daemon, if possible
190
my(%stats) = ();
191
my($donereadagent) = 0;
192
sub readagent {
193
    return "" if($donereadagent);
194
    $MSG = "";
195
    makesnmp() if(!$snmp);
196
    if($DEBUG and $VMWARESTATS) {
197
        open STATS,"$VMWARESTATS|" or return 0;
198
        while( <STATS> ) { 
199
#           print;
200
            chomp; $stats{$1}=$2 if(/^(\S+)\s*=\s*(\S.*)/); }
201
        close STATS;
202
        $donereadagent = 1;
203
        return 0;
204
    }
205
    $resp = $snmp->get_request( -varbindlist=>["$UCDOID.2.1"] ); 
206
    if(!$resp) {  # Fall back to the old way
207
        return 1;
208
    }
209
    if( $resp->{"$UCDOID.2.1"} ne 'vmware' ) {
210
        $MSG = "Incorrect SNMPD configuration: found '".$resp->{"$UCDOID.2.1"}."' when expected 'vmware'";
211
        $STATUS = $UNKNOWN;
212
        return 1;
213
    }
214
    $resp = $snmp->get_table( -baseoid=>"$UCDOID.101" ); 
215
    if(!$resp) {  # Fall back to the old way
216
#       $MSG = "SNMP error: ".$snmp->error;
217
        return 1;
218
    }
219
    # Convert the retrieved values to lookup hash
220
    foreach my $oid ( keys %$resp ) {
221
        if(( $oid =~ /\.101\.\d+$/ ) and ( $resp->{$oid}=~/^(\S+)=(.*)$/)) {
222
            $stats{$1}=$2; 
223
        }
224
    }
225
    $donereadagent = 1;
226
    return "";
227
}
228
229
###########################################################################
230
sub getesxversion {
231
    print "(snmp lookup)\n" if($DEBUG);
232
    makesnmp() if(!$snmp);
233
    $resp = $snmp->get_request( -varbindlist=>[ "$VMOID.1.2.0" ] );
234
    if(!$resp) {
235
        if(readagent) {
236
            $MSG = "Error: No VMWare SNMP sub-agent running (vmware-snmpd)"
237
                if(!$MSG);
238
            $STATUS = $UNKNOWN;
239
            dooutput; # exit
240
            exit(0);
241
        }
242
        if(!$stats{'has-names'}) {
243
            $MSG = "Error: No VMWare SNMP sub-agent running (vmware-snmpd)";
244
            $STATUS = $UNKNOWN;
245
            dooutput; # exit
246
            exit(0);
247
        }
248
        $esx_version = 2;  # just a blind assumption
249
    } else {
250
        $esx_version = $resp->{"$VMOID.1.2.0"};
251
        $esx_version =~ s/\..*//;
252
    }
253
}
254
255
# Read all the VM IDs from the vmware-snmpd MIB
256
sub getvmid {
257
    print "(snmp lookup)\n" if($DEBUG);
258
259
    makesnmp() if(!$snmp);
260
    if(!readagent and $stats{'has-names'}) {
261
        foreach ( keys %stats ) {
262
            if( /vhost-(\d+)-name/ ) {
263
                $lookup{$1} = $stats{$_}; # id->name
264
                $lookup{$stats{$_}} = "vmno-$1" ; # name->dummyOID
265
                $lookup{"vmno-$1"} = $1 ; # dummyOID->id
266
            }
267
        }
268
    } else {
269
        $resp = $snmp->get_table( -baseoid=>"$VMOID.2.1.1");
270
        if(!$resp) {
271
            $resp = $snmp->get_request( -varbindlist=>[ "$VMOID.1.1.0" ] );
272
            if(!$resp) {
273
                $MSG = "Error: No VMWare SNMP sub-agent running (vmware-snmpd)"
274
                    if(!$MSG);
275
                $STATUS = $UNKNOWN;
276
                dooutput; # exit 
277
                exit(0);
278
            } else {
279
                print "No guests are defined on this server\n" if($DEBUG);
280
                $MSG = "No guests defined on this server";
281
                return;
282
            }
283
        } else {
284
            foreach my $oid ( keys %$resp ) {
285
                $oid =~ /(\d+)\.(\d+)$/;
286
                if( $1 == 2 ) {
287
                    $lookup{$resp->{$oid}} = $2;
288
                    $lookup{$2} = $resp->{"$VMOID.2.1.1.7.$2"};
289
                    $lookup{$resp->{"$VMOID.2.1.1.7.$2"}} = $resp->{$oid};
290
                                $lookup{"vmGuestState-$2"} = $resp->{"$VMOID.2.1.1.8.$2"};
291
                }
292
            }
293
        }
294
    }
295
    return if(!$vhost); # we're just getting the table
296
    if(defined $lookup{$vhost}) {
297
        $VMNO = $lookup{$vhost};
298
        if( defined $lookup{$VMNO} ) {
299
            $VMID = $lookup{$VMNO};
300
            if ( defined $lookup{"vmGuestState-$VMNO"} ) {
301
                $vmGuestState = $lookup{"vmGuestState-$VMNO"};
302
            }
303
        } else {
304
            $STATUS = $CRITICAL;
305
            $MSG = "Virtual host $vhost($VMNO) is not running!";
306
        }
307
    } else {
308
        # lets see if they just gave part of the vhost name?
309
        $VMNO = "U";
310
        foreach ( keys %lookup ) {
311
            if( /^$vhost/i ) {
312
                $VMNO = $lookup{$_};
313
                if( defined $lookup{$VMNO} ) {
314
                    $VMID = $lookup{$VMNO};
315
                    if ( defined $lookup{"vmGuestState-$VMNO"} ) {
316
                        $vmGuestState = $lookup{"vmGuestState-$VMNO"};
317
                    }
318
                    $vhost = $_;
319
                } else {
320
                    $STATUS = $CRITICAL;
321
                    $MSG = "Virtual host $vhost($VMNO) is not running!";
322
                }
323
                last;
324
            }
325
        }
326
        if($VMNO eq "U") {
327
            $STATUS = $UNKNOWN;
328
            $MSG = "Virtual host $vhost is not defined!";
329
            dooutput; # exit 
330
            exit(0);
331
        }
332
    }
333
334
    print "(hostno=$VMNO, ID=$VMID)\n" if($DEBUG);
335
}
336
337
sub listvm {
338
    my(@vh);
339
    %lookup = (); @vh = ();
340
    print "(snmp lookup)\n" if($DEBUG);
341
    makesnmp() if(!$snmp);
342
    if(!readagent and $stats{'has-names'}) {
343
        foreach ( keys %stats ) {
344
            if( /vhost-(\d+)-name/ ) {
345
                $lookup{$1} = $stats{$_}; # id->name
346
                $lookup{$stats{$_}} = "vmno-$1" ; # name->dummyOID
347
                $lookup{"vmno-$1"} = $1 ; # dummyOID->id
348
                push @vh,$stats{$_};
349
            }
350
        }
351
    } else {
352
        $resp = $snmp->get_table( -baseoid=>"$VMOID.2.1.1");
353
        if(!$resp) {
354
            if(readagent) {
355
                $A = $B = 'U';
356
                $MSG = "Error: No VMWare SNMP sub-agent running (vmware-snmpd)"
357
                    if(!$MSG);
358
                $STATUS = $UNKNOWN;
359
                dooutput; # exit
360
                exit(0);
361
            }
362
            if(!$stats{'has-names'}) {
363
                $MSG = "Error: No VMWare SNMP sub-agent running (vmware-snmpd)";
364
                $STATUS = $UNKNOWN;
365
                dooutput; # exit
366
                exit(0);
367
            }
368
            foreach ( keys %stats ) {
369
                if( /vhost-(\d+)-name/ ) {
370
                    $lookup{$1} = $stats{$_}; # id->name
371
                    $lookup{$stats{$_}} = "vmno-$1" ; # name->dummyOID
372
                    $lookup{"vmno-$1"} = $1 ; # dummyOID->id
373
                    push @vh,$stats{$_};
374
                }
375
            }
376
377
        } else {
378
            foreach my $oid ( sort keys %$resp ) {
379
                $oid =~ /(\d+)\.(\d+)$/;
380
                if( $1 == 2 ) {
381
                    $lookup{$resp->{$oid}} = $2;
382
                    push @vh, $resp->{$oid};
383
                } elsif( $esx_version == 2 && $1 == 7 ) {
384
                    $lookup{$2} = $resp->{$oid};
385
                } elsif( $esx_version == 3 && $1 == 8 ) {
386
                    $lookup{$2} = $resp->{$oid};
387
                }
388
            }
389
390
        }
391
    } # stats available
392
    $A = $B = 0;
393
    foreach ( @vh ) { 
394
        next if(!$_);
395
        $B++; 
396
        if ( $esx_version == 2 ) {
397
            if( defined $lookup{$lookup{$_}} and ($lookup{$lookup{$_}} > 0)) {
398
                $_ = (substr $_,0,$TRUNC)."(".$lookup{$lookup{$_}}.")"; $A++;
399
            } else {
400
                $_ = (substr $_,0,$TRUNC)."(DOWN)";
401
            }
402
        } else {
403
            # This logic is for ESX 3.
404
        #print "$lookup{$lookup{$_}} \n";
405
            if( defined $lookup{$lookup{$_}} and ($lookup{$lookup{$_}} > 0 )) {
406
                $_ = (substr $_,0,$TRUNC)."(UP)"; $A++;
407
            } else {
408
                $_ = (substr $_,0,$TRUNC)."(DOWN)";
409
            }
410
        }
411
        $_ =~ s/ *\([^\)]+\)(\(.*\))/$1/;
412
    }
413
    $MSG = "VHosts: $A/$B up: ".(join ", ",@vh);
414
    push @perf, "allvms_up_ct=$A;;;0;$B";
415
    push @perf, "allvms_up_pc=". int($A/$B*10000)/100.0 ."%;;;0;100";
416
    $STATUS = $OK;
417
}
418
419
sub readnet {
420
    my($found);
421
422
    if($SNMPFILE and $DEBUG) {
423
        $resp = snmpfile("$VMOID.3.4.1");
424
    } else {
425
        $resp = $snmp->get_table( -baseoid=>"$VMOID.3.4.1");
426
    }
427
    if(!$resp) {
428
        $resp = $snmp->get_request( -varbindlist=>[ "$VMOID.1.1" ] );
429
        if($resp) { $A = $B = 0; 
430
            $MSG = "No VHosts defined"; $STATUS = $OK; return; }
431
        $MSG = "Error: Unable to retrieve SNMP data";
432
        $STATUS = $UNKNOWN;
433
        return;
434
    }
435
    foreach my $oid ( keys %$resp ) {
436
        $oid =~ /(\d+)\.(\d+)$/; # Type, index.
437
        if( $1 == 3 ) {
438
            $tmpnet{$2} = [ 
439
                $resp->{$oid},
440
                $resp->{"$VMOID.3.4.1.2.$2"},
441
                ($resp->{"$VMOID.3.4.1.7.$2"}*1024),
442
                ($resp->{"$VMOID.3.4.1.9.$2"}*1024)
443
            ];
444
        }
445
    }
446
    return if($opt_l =~ /LIST/);
447
    # We now have all the network statistics indexed by card or VMID
448
    $A = $B = 0; $found = 0;
449
    foreach ( keys %tmpnet ) {
450
        if((($VMID<0) or ($VMID == $tmpnet{$_}[0])) # vm matches
451
            and ((!$opt_i) or ($opt_i eq $tmpnet{$_}[1]))) { # net matches
452
            $A += $tmpnet{$_}[2];
453
            $B += $tmpnet{$_}[3];
454
            $found = 1;
455
        }
456
    }
457
    if(!$found) {
458
        $MSG = "No network interfaces exist for ";
459
        $MSG .= "vhost $vhost" if($VMID>-1);
460
        $MSG .= " and " if($VMID>-1 and $opt_i);
461
        $MSG .= " interface $opt_i" if ($opt_i);
462
        $STATUS = $UNKNOWN;
463
    }
464
}
465
466
###########################################################################
467
# Read general memory and CPU data from vmware-snmpd
468
# This is what we do if we can't get the detailed information.
469
sub readcpu {
470
    my($k,@k);
471
    my($t1,$t2,$a1);
472
473
    $MSG = ""; $A = 0; $B = 0;
474
    if( !$MODE or $opt_r ) { 
475
        readstate; 
476
        $t1 = $states{"$hostname-CPU-$vhost-time"}; 
477
        $a1 = $states{"$hostname-CPU-$vhost"}; 
478
        $t2 = time;
479
    }
480
481
    @k = ();
482
    if( $VMID < 0 ) {
483
        foreach ( keys %lookup ) {
484
            push @k, "$VMOID.3.1.2.1.3.".$_ if( /^\d+$/ and $_>99);
485
        }
486
    } else {
487
        $k = "$VMOID.3.1.2.1.3.$VMID";
488
        @k = ( $k );
489
    }
490
    foreach $k ( @k ) { print "(retrieving $k)\n" if($DEBUG); }
491
    $resp = $snmp->get_request( -varbindlist=>\@k );
492
    if( $resp ) {
493
        if($VMID<0){
494
            $A = 0;
495
            foreach ( keys %$resp ) { $A += $resp->{$_}; 
496
                print "$_: ".$resp->{$_}."\n" if($DEBUG); }
497
        } else {
498
            $A = $resp->{$k}; 
499
        }
500
        $B = 0;
501
    } else {
502
        $A = $B = 'U';
503
        if($VMID<0){
504
            $MSG = "Unable to retrieve CPU statistics for ESX server: ".$snmp->error;
505
        } else {
506
            $MSG = "Unable to retrieve CPU statistics for $vhost: ".$snmp->error;
507
        }
508
        $STATUS = $UNKNOWN;
509
    }
510
    if(!$MSG){ # IE, no errors
511
        $MSG = "CPU has used $A seconds";
512
        $MSG .= " on $vhost" if($vhost);
513
        if( !$MODE or $opt_r ) { 
514
            writestate( "$hostname-CPU-$vhost"=>$A, "$hostname-CPU-$vhost-time"=>$t2 )
515
                if(!$t1 or ($t2-$t1)>30); 
516
            if(!$t1 or !$a1 or ($t1 >= $t2) or ( ($t2-$t1)>1000 ) ) {   
517
                if($vhost) {
518
                    $MSG = "No saved state for $vhost CPU time yet - please wait for next poll.";   
519
                } else {
520
                    $MSG = "No saved state for ESX system CPU time yet - please wait for next poll.";
521
                }
522
                $A = $B = "U";
523
                $STATUS = $UNKNOWN;
524
            } else {
525
                print "Usage: $A-$a1 in $t2-$t1 = ".($A-$a1)." in ".($t2-$t1)
526
                    if($DEBUG);
527
                $A = int((($A - $a1)/($t2 - $t1))*10000)/100;
528
                print " = $A\n" if($DEBUG);
529
                $B = 0;
530
                $MSG = "CPU usage is $A% ";
531
                $MSG .= "on $vhost" if($vhost);
532
                $MSG .= " (".($t2-$t1)."s average)";
533
                if($A>110 or $A<0) {
534
                    $B = $A = 0;
535
                    $MSG = "Error reading CPU usage information."
536
                }
537
            }
538
        }
539
    }
540
}
541
542
sub readmem {
543
    my($k1,$k2);
544
545
    if($VMID < 0) {
546
        $k1 = "$VMOID.3.2.1.0"; #   Total physical present
547
        $k2 = "$VMOID.3.2.3.0"; #   Memory free
548
    } else {
549
        $k1 = "$VMOID.3.2.4.1.3.$VMID"; # VM memory max
550
        $k2 = "$VMOID.3.2.4.1.4.$VMID"; # VM memory used
551
    }
552
    print "(retrieving $k1,$k2)\n" if($DEBUG);
553
    $resp = $snmp->get_request( -varbindlist=>[$k1,$k2] );
554
    if( $resp ) {
555
        if($VMID < 0 ) {
556
            $A = $resp->{$k2}; $B = $resp->{$k1};
557
        } else {
558
            $A = $resp->{$k2}; $B = $resp->{$k1};
559
            $B *= 1024 if($B<10240 or $B<$A); # ESX3 gives it in Kb, ESX2 gives it in Mb (argh!)
560
            # we can assume noone has a VM with <10Mb or >10Gb!
561
            $A = $B - $A; # memory remaining
562
        }
563
    } else {
564
        $A = $B = 'U';
565
        if($VMID<0) {
566
        $MSG = "Unable to retrieve memory statistics for ESX server: ".$snmp->error;
567
        } else {
568
        $MSG = "Unable to retrieve memory statistics for $vhost: ".$snmp->error;
569
        }
570
        $STATUS = $UNKNOWN;
571
    }
572
}
573
sub readconsolemempc {
574
    my($k1,$k2);
575
576
    $k1 = "$VMOID.3.2.1.0"; # Total physical present (vmwMemory.memSize.0)
577
    $k2 = "$VMOID.3.2.2.0"; # Memory used by console (vmwMemory.memCOS.0)
578
    print "(retrieving $k1,$k2)\n" if($DEBUG);
579
    $resp = $snmp->get_request( -varbindlist=>[$k1,$k2] );
580
    if( $resp ) {
581
        return int( $resp->{$k2} / $resp->{$k1} * 10000) / 100.0;
582
    } else {
583
        return 'U';
584
    }
585
}
586
587
sub vmavgready {
588
    my($c) = 0;
589
    my($t) = 0;
590
    foreach my $k ( keys %stats ) {
591
        if( $k =~ /vhost-.*-cpu-ready-pc/ ) {
592
            $c += 1;
593
            $t += $stats{$k};
594
            print "$k : ".$stats{$k}."\n" if($DEBUG);
595
        }
596
    }
597
    print "$c vhosts total ready $t, avg is ".($t/$c)."\n" if($DEBUG);
598
    return ($c?($t/$c):undef);
599
}
600
sub readrpc {
601
    $MSG = ""; $A = 0; $B = 0; $STATUS = 0;
602
    if( readagent ) {
603
        $A = $B = "U";
604
        print "(readagent failed: $MSG)\n" if($DEBUG);
605
        $STATUS = 3 if(!$STATUS); 
606
        $MSG = "Unable to retrieve statistics" if(!$MSG);   
607
        dooutput;
608
        exit $STATUS;
609
    }
610
    if( ! $stats{'has-rpc'} ) {
611
        $A = $B = "U";
612
        print "(old version agent)\n" if($DEBUG);
613
        $STATUS = 3 if(!$STATUS); 
614
        $MSG = "Remote agent does not support RPC: upgrade to vmware-stats v2.5 or later!"; 
615
        dooutput;
616
        exit $STATUS;
617
    }
618
    if($vhost) {
619
        $A = $stats{"vhost-$VMID-rpc-count"};
620
        $B = $stats{"vhost-$VMID-rpc-rate"};
621
        if(!defined $A) { $A= $B = 'U'; $MSG="Unable to retrieve data";
622
            $STATUS = 3; dooutput; exit 3; }
623
        $B = 0 if(!$B);
624
    } else {
625
        $A = $B = 0;
626
        foreach ( keys %stats ) {
627
            $A += $stats{$_} if( /-rpc-count/ );
628
            $B += $stats{$_} if( /-rpc-rate/ );
629
        }
630
    }
631
}
632
sub readxcpu {
633
    my($k,$C);
634
    $MSG = ""; $A = 0; $B = 0; $STATUS = 0;
635
    if( readagent ) {
636
        print "(readagent failed: $MSG)\n" if($DEBUG);
637
        readcpu if(!$MSG); # no vmware agent, no error
638
        return;
639
    }
640
    if($vhost) { 
641
        if ( $esx_version <= 2 ) {
642
            $k = "vhost-$VMID";
643
        } else {
644
            foreach my $key ( keys %stats ) {
645
                if ( $stats{$key} eq $lookup{$lookup{$VMNO}} ) {
646
                    $key =~ /vhost-(\d+)-name/;
647
                    $k = "vhost-$1";
648
                    last;
649
                }
650
            }
651
        }
652
        if ( defined $k ) {
653
            $A = $stats{"$k-cpu-used-pc"};
654
            $B = $stats{"$k-cpu-ready-pc"};
655
        } else {
656
            $A = undef;
657
            $B = undef;
658
        }
659
        $C = $A;
660
    } else { 
661
        $k = "sys"; 
662
        if($opt_a) {
663
            $A = $stats{"sys-cpu-used-pc"} + $stats{"allvms-cpu-used-pc"}
664
                if($stats{"allvms-cpu-used-pc"});
665
            $B = vmavgready();
666
            $C = $B if(defined $B);
667
        } else {
668
            $A = $stats{"sys-cpu-used-pc"};
669
            $B = $stats{"allvms-cpu-used-pc"};
670
            $C = $A + $B if(defined $A and defined $B);
671
        }
672
    }
673
    if(!defined $A or !defined $B) {
674
        $A=$B='U'; $MSG="No saved CPU statistics available - please wait for next poll.";
675
        $STATUS = 3;
676
        # Fill in some dummy performance data anyway, to keep downstream processes somewhat happy.
677
        if ($vhost) {
678
            push @perf, "vhost_cpu_used_pc=U%;;;0;100";
679
            push @perf, "vhost_cpu_ready_pc=U%;;;0;100";
680
        } else {
681
            push @perf, "sys_cpu_used_pc=U%;;;0;100";
682
            push @perf, "allvms_cpu_used_pc=U%;;;0;100";
683
            push @perf, "sys_cpu_ready_pc=U%;;;0;100";
684
        }
685
686
        dooutput; exit 3;
687
    }
688
689
    if($opt_a) {
690
        if($vhost) { $MSG = "vhost CPU used=$A% ready=$B%"; }
691
        else { $MSG = "CPU used total=$A% avgvhostreadytime=$B%"; }
692
    } else {
693
        if($vhost) { $MSG = "vhost CPU used=$A% ready=$B%"; }
694
        else { $MSG = "CPU used sys=$A% vhosts=$B% sysreadytime="
695
            .$stats{'sys-cpu-ready-pc'}."%"; }
696
    }
697
698
    if($vhost) {
699
        $MSG = "vhost CPU used=$A% ready=$B%";
700
        push @perf, "vhost_cpu_used_pc=$A%;;;0;100";
701
        push @perf, "vhost_cpu_ready_pc=$B%;;;0;100";
702
    } else {
703
        $MSG = "CPU used sys=$A% vhosts=$B% readytime=".$stats{'sys-cpu-ready-pc'}."%";
704
        push @perf, "sys_cpu_used_pc=$A%;;;0;100";
705
        push @perf, "allvms_cpu_used_pc=$B%;;;0;100";
706
        push @perf, "sys_cpu_ready_pc=".$stats{'sys-cpu-ready-pc'}."%;;;0;100";
707
    }
708
709
    # MRTG only
710
    if($MODE) { dooutput; exit 0; } 
711
    # Nagios only
712
    if(!$vhost and $opt_a) {
713
        if($C>=$rcrit) {
714
            $MSG .= "<BR>" if($MSG);
715
            $MSG .= "Ready time is CRITICAL ($C\%)";
716
            $STATUS = 2;
717
        } elsif($C>=$rwarn) {
718
            $MSG .= "<BR>" if($MSG);
719
            $MSG .= "Ready time is WARNING ($C\%)";
720
            $STATUS = 1 if($STATUS<2);
721
        }
722
    } else {
723
    $crit =~ s/[^\d\.]//g; $warn =~ s/[^\d\.]//g;
724
    $crit = 100 if(!$crit); $warn = 100 if(!$warn);
725
    if( $C >= $crit ) {
726
        $MSG .= "<BR>" if($MSG);
727
        $MSG .= "CPU usage is CRITICAL ($C\%)";
728
        $STATUS = 2;
729
    } elsif( $C >= $warn ) {
730
        $MSG .= "<BR>" if($MSG);
731
        $MSG .= "CPU usage is WARNING ($C\%)";
732
        $STATUS = 1 if($STATUS<2);
733
    }
734
735
    # Ready time
736
    if( $stats{"$k-cpu-ready-pc"} >= $rcrit ) {
737
        $MSG .= "<BR>" if($MSG);
738
        $MSG .= "Ready time is CRITICAL (".$stats{"$k-cpu-ready-pc"}."\%)";
739
        $STATUS = 2;
740
    } elsif( $stats{"$k-cpu-ready-pc"} >= $rwarn ) {
741
        $MSG .= "<BR>" if($MSG);
742
        $MSG .= "Ready time is WARNING (".$stats{"$k-cpu-ready-pc"}."\%)";
743
        $STATUS = 1 if($STATUS<2);
744
    }   
745
    }
746
    if(!$vhost) { # check all vhosts
747
        foreach ( keys %lookup ) {
748
            next if(!defined $stats{"vhost-$_-cpu-used-pc"});
749
            $C=$stats{"vhost-$_-cpu-used-pc"};
750
            if( $C >= $crit ) {
751
                $MSG .= "<BR>" if($MSG);
752
                $MSG .= "'".base($lookup{$_})."' CPU CRITICAL ($C\%)";
753
                $STATUS = 2;
754
            } elsif( $C >= $warn ) {
755
                $MSG .= "<BR>" if($MSG);
756
                $MSG .= "'".base($lookup{$_})."' CPU WARNING ($C\%)";
757
                $STATUS = 1 if($STATUS<2);
758
            }
759
            if( $stats{"vhost-$_-cpu-ready-pc"} >= $rcrit ) {
760
                $MSG .= "<BR>" if($MSG);
761
                $MSG .= "'".base($lookup{$_})."' Ready time CRITICAL (".$stats{"vhost-$_-cpu-ready-pc"}."\%)";
762
                $STATUS = 2;
763
            } elsif( $stats{"vhost-$_-cpu-ready-pc"} >= $rwarn ) {
764
                $MSG .= "<BR>" if($MSG);
765
                $MSG .= "'".base($lookup{$_})."' Ready time WARNING (".$stats{"vhost-$_-cpu-ready-pc"}."\%)";
766
                $STATUS = 1 if($STATUS<2);
767
            }
768
        }
769
    }
770
    dooutput;
771
    exit 3; # not reached
772
}
773
sub readxmem {
774
    my($pc,$max,$k,$memVMID);
775
776
    $MSG = ""; $A = 0; $B = 0;
777
    if( readagent() ) {
778
        print "(readagent failed: $MSG)\n" if($DEBUG);
779
        readmem if(!$MSG); # no vmware agent, no error
780
        return;
781
    }
782
783
    if( $vhost ) {
784
        if ( $esx_version <= 2 ) {
785
            $k = "vhost-$VMID";
786
        } else {
787
            # for ESX Version 3
788
            foreach my $key ( keys %stats ) {
789
                if ( $stats{$key} eq $lookup{$lookup{$VMNO}} ) {
790
                    $key =~ /vhost-(\d+)-name/;
791
                    $memVMID = $1 - 1;  # why this is off by one, we don't know, but it is
792
                    $k = "unknown-$memVMID";
793
                    last;
794
                }
795
            }
796
        }
797
        $A = $stats{"$k-mem-active"};
798
        $B = $stats{"$k-mem-max"};
799
        $max = $stats{"$k-mem-max"};
800
801
        if(!defined $A or !defined $B) { $A=$B='U'; 
802
            $MSG="Problem reading memory data on ESX server"; $STATUS=3;
803
            push @perf, "vhost_mem_act_pc=U\%;;;0;100";
804
            push @perf, "vhost_mem_pvt_pc=U\%;;;0;100";
805
            push @perf, "vhost_mem_shr_pc=U\%;;;0;100";
806
            push @perf, "vhost_mem_bal_pc=U\%;;;0;100";
807
            push @perf, "vhost_mem_swp_pc=U\%;;;0;100";
808
            dooutput; exit 0;
809
        }
810
        $pc = int($A/$B*10000)/100.0;
811
        $MSG = "Memory active: ".int($A/1024000)."Mb ($pc\%) [Total available ".int($B/1024000)."Mb]";
812
        push @perf, "vhost_mem_act_pc=$pc\%;;;0;100";
813
        if($pc>=$crit) { $STATUS=2; $MSG = "CRIT: $MSG"; }
814
        elsif($pc>=$warn) { $STATUS=1; $MSG = "WARN: $MSG"; }
815
        if($opt_a) { $A = $B = $pc; }
816
    } else {
817
        $k = "allvms";
818
#       $A = $stats{'mem-avail'}; 
819
#       $B = $stats{'mem-total'};
820
        $A = $stats{'mem-free'};
821
        $B = $stats{'mem-total'};
822
        $max = $stats{"$k-mem-max"};
823
        if(!defined $A or !defined $B) { $A=$B='U'; 
824
            $MSG="Problem reading memory data on ESX server."; $STATUS=3;
825
            push @perf, "mem_free_pc=U\%;;;0;100";
826
            if ( $esx_version == 3 ) {
827
                push @perf, "console_mem_pc=U\%;;;0;100";
828
            }
829
            push @perf, "allvms_mem_pvt_pc=U\%;;;0;100";
830
            push @perf, "allvms_mem_shr_pc=U\%;;;0;100";
831
            push @perf, "allvms_mem_bal_pc=U\%;;;0;100";
832
            push @perf, "allvms_mem_swp_pc=U\%;;;0;100";
833
            dooutput; exit 0;
834
        }
835
        $pc = int($A/$B*10000)/100.0;
836
        $MSG = "Memory unreserved: ".int($A/1024000)."Mb ($pc\%) [Total managed ".int($B/1024000)."Mb]";
837
        push @perf, "mem_free_pc=$pc\%;;;0;100";
838
        if ( $esx_version == 3 ) {
839
            my ($consolemempc) = readconsolemempc;
840
            $MSG .= " [Console=$consolemempc\%]";
841
            push @perf, "console_mem_pc=" . $consolemempc . "\%;;;0;100";
842
        }
843
        if($pc<=$crit) { $STATUS=2; $MSG = "CRIT: $MSG"; }
844
        elsif($pc<=$warn) { $STATUS=1; $MSG = "WARN: $MSG"; }
845
        if($opt_a) { 
846
            $MSG = "Memory used: ".int(($B-$A)/1024000)."Mb (".(100-$pc)."\%) [Total available ".int($B/1024000)."Mb]";
847
            $A = 100 - $pc; $B = $pc; 
848
        }
849
    }
850
851
    # MRTG
852
    if($MODE) { dooutput; exit 0; }
853
854
    # Nagios    
855
    if($max) {
856
        $MSG .= "<BR>Memory split: pvt/shr/bal/swp = "
857
            .(int(10000*$stats{"$k-mem-private"}/$max)/100.0)."\%/"
858
            .(int(10000*$stats{"$k-mem-shared"}/$max)/100.0)."\%/"
859
            .(int(10000*$stats{"$k-mem-balloon"}/$max)/100.0)."\%/"
860
            .(int(10000*$stats{"$k-mem-swap"}/$max)/100.0)."\%";
861
        if ($vhost) {
862
            push @perf, "vhost_mem_pvt_pc=" . (int(10000*$stats{"$k-mem-private"}/$max)/100.0) . "\%;;;0;100";
863
            push @perf, "vhost_mem_shr_pc=" . (int(10000*$stats{"$k-mem-shared" }/$max)/100.0) . "\%;;;0;100";
864
            push @perf, "vhost_mem_bal_pc=" . (int(10000*$stats{"$k-mem-balloon"}/$max)/100.0) . "\%;;;0;100";
865
            push @perf, "vhost_mem_swp_pc=" . (int(10000*$stats{"$k-mem-swap"   }/$max)/100.0) . "\%;;;0;100";
866
        } else {
867
            push @perf, "allvms_mem_pvt_pc=" . (int(10000*$stats{"$k-mem-private"}/$max)/100.0) . "\%;;;0;100";
868
            push @perf, "allvms_mem_shr_pc=" . (int(10000*$stats{"$k-mem-shared" }/$max)/100.0) . "\%;;;0;100";
869
            push @perf, "allvms_mem_bal_pc=" . (int(10000*$stats{"$k-mem-balloon"}/$max)/100.0) . "\%;;;0;100";
870
            push @perf, "allvms_mem_swp_pc=" . (int(10000*$stats{"$k-mem-swap"   }/$max)/100.0) . "\%;;;0;100";
871
        }
872
    
873
        if($stats{"$k-mem-balloon"}) {
874
            $pc = int(100000*$stats{"$k-mem-balloon"}/$max)/1000.0;
875
            if($pc>=25) {
876
                $MSG .= "<BR>CRIT: Balloon drivers in action! ($pc\%)";
877
                $STATUS = 2;
878
            } elsif($pc>=0.01) {
879
                $MSG .= "<BR>WARN: Balloon drivers in action! ($pc\%)";
880
                $STATUS = 1 if($STATUS<2);
881
            }
882
        }
883
    }
884
    if($stats{"$k-swap-in-bps"} and $stats{"$k-swap-in-bps"}>10) {
885
        if($stats{"$k-swap-in-bps"}>$SWAPINCRIT) {
886
            $MSG .= "<BR>CRIT: VMware swapping in action! (".$stats{"$k-swap-in-bps"}."Bps)";
887
            $STATUS = 2;
888
        } else {
889
            $MSG .= "<BR>WARN: VMware swapping is starting!";
890
            $STATUS = 1 if($STATUS<2);
891
        }
892
    } elsif($max and $stats{"$k-mem-swap"}) {
893
        $pc = int(100000*$stats{"$k-mem-swap"}/$max)/1000.0;
894
        if($pc>=$SWAPPCCRIT) {
895
            $MSG .= "<BR>CRIT: VMWare swap space in use! ($pc\%)";
896
            $STATUS = 2;
897
        } elsif($pc>=$SWAPPCWARN) {
898
            $MSG .= "<BR>WARN: VMWare swap space in use! ($pc\%)";
899
            $STATUS = 1 if($STATUS<2);  
900
        }
901
    }
902
903
    dooutput;
904
    exit 3; # not reached
905
}
906
907
###########################################################################
908
getopts('vahrdNMH:c:t:V:w:C:l:i:R:');
909
$hostname = $opt_H if($opt_H);
910
$vhost = $opt_V if($opt_V);
911
$warn = $opt_w if($opt_w);
912
$crit = $opt_c if($opt_c);
913
$TIMEOUT = $opt_t if($opt_t);
914
$RETRIES = $opt_R if($opt_R);
915
$MODE = 1 if($opt_M);
916
$community = $opt_C if($opt_C);
917
$DEBUG = 1 if($opt_d);
918
dohelp if($opt_h);
919
920
if($opt_v) {
921
    print "(did you mean to use -V?) " if($opt_C or $opt_H);
922
    print "check_esx version $VERSION\n";
923
    exit 0;
924
}
925
if(!$hostname) {
926
    $MSG = "No ESX server hostname specified with -H";
927
    dooutput;
928
    exit 0;
929
}
930
if( !$opt_l  ) {
931
#   $MSG = "You need to specify a command with -l";
932
#   dooutput;
933
#   exit 0;
934
    $opt_l = "LIST";
935
}
936
getesxversion;
937
if( $opt_l =~ /LISTNET/i ) {
938
    getvmid;
939
    $MSG = "";
940
    readnet;
941
    if(!$MSG) {
942
        my($tk);
943
        foreach ( keys %tmpnet ) {
944
            if(!$vhost or ($VMID eq $tmpnet{$_}[0]) ) {
945
                $tk=$tmpnet{$_}[1];
946
                next if($MSG=~/$tk/);
947
                $MSG .= ', ' if($MSG);
948
#               $MSG .= $lookup{$tmpnet{$_}[0]}."/" if(!$opt_v);
949
                $MSG .= $tk;
950
            }
951
        }
952
        $STATUS = $OK;
953
    }
954
    dooutput;
955
    exit 0;
956
}
957
if( $opt_l =~ /LIST/i ) {
958
    listvm;
959
    if(!$opt_w) { $warn = $B - 1; }
960
    if(!$opt_c) { $crit = 0; }
961
    if($warn =~ /(\d+)\%/) {
962
        $warn = $B * $1 / 100;
963
    } elsif( $warn < 0 ) { $warn = $B - 1; }
964
    if($crit =~ /(\d+)\%/) {
965
        $crit = $B * $1 / 100;
966
    } elsif( $crit < 0 ) { $crit = 0; }
967
    $STATUS = $WARNING if($A<=$warn); # If SOME are down
968
    $STATUS = $CRITICAL if($A<=$crit); # If NONE are up
969
    $STATUS = $OK if(!$B); # No guests at all
970
    dooutput;
971
    exit 3;
972
}
973
if( $opt_l !~ /NET|CPU|MEM|STAT|RPC/i ) {
974
    $MSG = "Bad command $opt_l!";
975
    dooutput;
976
    exit 3;
977
}
978
if( $opt_l =~ /MEM|CPU|NET|RPC/ and !$MODE and ($crit<0 or $warn<0)) {
979
    $MSG = "Invalid warn/critical thresholds for '$opt_l' (need -w and -c)"; 
980
    dooutput;
981
    exit 3;
982
}
983
984
985
# Now, we have host, vhost, community, and command
986
getvmid; # also opens SNMP object
987
if( $opt_l =~ /STAT/i ) {
988
    if(!$vhost) {
989
        $MSG = "No virtual hostname specified with -v";
990
        dooutput;
991
        exit 0;
992
    }
993
    if( ( $esx_version == 2 && $VMID < 0 ) || ( $esx_version == 3 && $vmGuestState ne "running" ) ) {
994
        $STATUS = $CRITICAL; ($A,$B) = (0,0);
995
        $MSG = "VHost $vhost is down or undefined.";
996
    } else {
997
        $STATUS = $OK; ($A,$B) = (1,1);
998
        $MSG = "VHost $vhost is up (ID: $VMID)";
999
    }
1000
    push @perf, "vhost_up=$A;;;0;1";
1001
    dooutput;
1002
    exit 0;
1003
}
1004
if($vhost and ( $esx_version == 2 && $VMID < 0 || $esx_version == 3 && $vmGuestState ne "running" )) {
1005
    $STATUS = $CRITICAL;
1006
    $MSG = "$vhost is not running." if(!$MSG);
1007
    if( $opt_l =~ /CPU/i ) {
1008
        # Fill in some dummy performance data anyway, to keep downstream processes happy.
1009
        push @perf, "vhost_cpu_used_pc=U%;;;0;100";
1010
        push @perf, "vhost_cpu_ready_pc=U%;;;0;100";
1011
    }
1012
    if( $opt_l =~ /MEM/i ) {
1013
        # Fill in some dummy performance data anyway, to keep 
1014
        # downstream processes happy.
1015
        push @perf, "vhost_mem_act_pc=U%;;;0;100";
1016
        push @perf, "vhost_mem_pvt_pc=U%;;;0;100";
1017
        push @perf, "vhost_mem_shr_pc=U%;;;0;100";
1018
        push @perf, "vhost_mem_bal_pc=U%;;;0;100";
1019
        push @perf, "vhost_mem_swp_pc=U%;;;0;100";
1020
    }
1021
    if( $opt_l =~ /NET/i ) {
1022
        # Fill in some dummy performance data anyway, to keep 
1023
        #downstream processes happy.
1024
        push @perf, "vhost_net_read=U;;;0";
1025
        push @perf, "vhost_net_write=U;;;0";
1026
    }
1027
    dooutput;
1028
    exit 0;
1029
}
1030
1031
$STATUS = $OK;
1032
if( $opt_l =~ /CPU/i ) {    
1033
    $warn = 70 if(!$opt_w);
1034
    $crit = 90 if(!$opt_c);
1035
    $MSG = "";
1036
    readxcpu; # attempt to use extended MIB, else use VMWare MIB
1037
} elsif( $opt_l =~ /NET/i ) {   
1038
    my($t1,$t2,$a1,$b1);
1039
    $opt_i = "" if(!defined $opt_i);
1040
    $vhost = "" if(!defined $vhost);
1041
    if( !$MODE or $opt_r ) { 
1042
        readstate; 
1043
        $t1 = $states{"$hostname-NET-$vhost-$opt_i-time"}; 
1044
        $a1 = $states{"$hostname-NET-$vhost-$opt_i-r"}; 
1045
        $b1 = $states{"$hostname-NET-$vhost-$opt_i-w"}; 
1046
        $t2 = time;
1047
    }
1048
    $MSG = "";
1049
    readnet;
1050
    if(!$MSG){ # IE, no errors
1051
        $MSG = "Network counters Read=$A Write=$B";
1052
        $MSG .= " on $vhost" if($vhost);
1053
        if( $opt_i ) {
1054
            if( $vhost ) { $MSG .= '/'; } else { $MSG .= ' on '; }
1055
            $MSG .= $opt_i;
1056
        }
1057
        if( !$MODE or $opt_r ) { 
1058
            writestate( "$hostname-NET-$vhost-$opt_i-r"=>$A, 
1059
                "$hostname-NET-$vhost-$opt_i-w"=>$B, 
1060
                "$hostname-NET-$vhost-$opt_i-time"=>$t2 ) 
1061
                if(!$t1 or ($t2-$t1)>30); 
1062
            if(!$t1 or (!$a1 and !$b1) or ($t1 >= $t2) or (($t2 - $t1)>3600)) { 
1063
                $MSG = "Gathering network statistics - please wait for next poll."; 
1064
                $A = $B = "U";
1065
                $STATUS = $UNKNOWN;
1066
                if ($vhost) {
1067
                    push @perf, "vhost_net_read=U;;;0";
1068
                    push @perf, "vhost_net_write=U;;;0";
1069
                } else {
1070
                    push @perf, "allvms_net_read=U;;;0";
1071
                    push @perf, "allvms_net_write=U;;;0";
1072
                }
1073
            } else {
1074
                $A = ($A - $a1)/($t2 - $t1);
1075
                $B = ($B - $b1)/($t2 - $t1);
1076
                ($fa,$sa,$fb,$sb) = ( $A, "", $B, "" );
1077
                if($fa >= 1048576) { $fa /= 1048576; $sa = 'M'; }
1078
                elsif($fa >= 1024) { $fa /= 1024; $sa = 'K'; }
1079
                if($fb >= 1048576) { $fb /= 1048576; $sb = 'M'; }
1080
                elsif($fb >= 1024) { $fb /= 1024; $sb = 'K'; }
1081
                $fa = int($fa * 100)/100; $fb = int($fb * 100)/100;
1082
                $MSG = "Network traffic $fa ".$sa."B/s read, $fb ".$sb."B/s write ";
1083
                $MSG .= "on $vhost" if($vhost);
1084
                if( $opt_i ) {
1085
                    if( $vhost ) { $MSG .= '/'; } else { $MSG .= 'on '; }
1086
                    $MSG .= $opt_i;
1087
                }
1088
                $MSG .= " (".($t2-$t1)."s average)";
1089
                if ($vhost) {
1090
                    push @perf, "vhost_net_read=".(int(100*$A)/100.0).";;;0";
1091
                    push @perf, "vhost_net_write=".(int(100*$B)/100.0).";;;0";
1092
                } else {
1093
                    push @perf, "allvms_net_read=".(int(100*$A)/100.0).";;;0";
1094
                    push @perf, "allvms_net_write=".(int(100*$B)/100.0).";;;0";
1095
                }
1096
            }
1097
        }
1098
    }
1099
} elsif( $opt_l =~ /MEM/i ) {   
1100
    my($pc,$tot,$av,$sfx);
1101
    $MSG = "";
1102
    if($opt_v) {
1103
        $warn = 70 if(!$opt_w);
1104
        $crit = 90 if(!$opt_c);
1105
    } else {
1106
        $warn = 30 if(!$opt_w);
1107
        $crit = 10 if(!$opt_c);
1108
    }
1109
    readxmem;
1110
    if(!$MSG) {
1111
        $pc = int($A/$B*10000.0)/100.0; 
1112
        $sfx = "Kb"; $av = $A;
1113
        if($av>2047) { $av = int($av/10.24)/100.0; $sfx="Mb"; }
1114
        $av .= $sfx;
1115
        $sfx = "Kb"; $tot = $B;
1116
        if($tot>2047) { $tot = int($tot/10.24)/100.0; $sfx="Mb"; }
1117
        $tot .= $sfx;
1118
        $MSG = "Memory free: $av ($pc\%) [Total available $tot]" ;
1119
        $MSG .= " on vhost $vhost" if($vhost);
1120
    }
1121
} elsif( $opt_l =~ /RPC/i ) {   
1122
    $MSG = "";
1123
    readrpc;
1124
    if(!$MSG) {
1125
        $MSG = "RPC calls ".(int($B*100)/100)."/sec (Total: $A)";
1126
    }
1127
} else {
1128
    $MSG = "Invalid command $opt_l";
1129
    $STATUS = $UNKNOWN;
1130
}
1131
1132
if( !$MODE and $STATUS==$OK ) {
1133
    # Set Nagios thresholds
1134
    if( $opt_l=~/MEM/i and $warn =~ /([\d\.]+)%/ ) { $warn = $B * $1 / 100.0; }
1135
    elsif( $warn =~ /([\d\.]+)M/i ) { $warn = $1 * 1024; }
1136
    elsif( $warn =~ /([\d\.]+)/i ) { $warn = $1; }
1137
    if( $opt_l=~/MEM/i and $crit =~ /([\d\.]+)%/ ) { $crit = $B * $1 / 100.0; }
1138
    elsif( $crit =~ /([\d\.]+)M/i ) { $crit = $1 * 1024; }
1139
    elsif( $crit =~ /([\d\.]+)/i ) { $crit = $1; }
1140
    if( $opt_l =~ /MEM/i ) {
1141
        print "$A : $warn : $crit \n" if ($DEBUG);
1142
        $STATUS = $WARNING  if( $A <= $warn );
1143
        $STATUS = $CRITICAL if( $A <= $crit );
1144
    } elsif( $opt_l =~ /CPU/i ) {
1145
        $STATUS = $WARNING  if( ($A+$B) >= $warn );
1146
        $STATUS = $CRITICAL if( ($A+$B) >= $crit );
1147
    } elsif( $opt_l =~ /NET/i ) {
1148
        $STATUS = $WARNING  if( $A >= $warn );
1149
        $STATUS = $WARNING  if( $B >= $warn );
1150
        $STATUS = $CRITICAL if( $A >= $crit );
1151
        $STATUS = $CRITICAL if( $B >= $crit );
1152
    } elsif( $opt_l =~ /RPC/i ) {
1153
        $STATUS = $WARNING  if( $B >= $warn );
1154
        $STATUS = $CRITICAL if( $B >= $crit );
1155
    } else {
1156
        $STATUS = $WARNING  if( $A <= $warn );
1157
        $STATUS = $CRITICAL if( $A <= $crit );
1158
    }
1159
}
1160
1161
$snmp->close if($snmp);;
1162
dooutput;
1163
exit 0;
1164