File check_drbd of Package nagios-plugins-drbd
1
#!/usr/bin/perl -w
2
3
####################################################
4
# check_drbd v0.5.3 #
5
# by Brandon Lee Poyner bpoyner / CCAC.edu #
6
####################################################
7
8
use strict;
9
use File::Basename;
10
use Getopt::Long;
11
12
my $drbd_proc='/proc/drbd';
13
my $drbd_devices=0;
14
my ($drbd_expect, $drbd_role, $drbd_version, $debug_mode);
15
my (%options, %cs, %st, %ld, %ds, %check, %warning, %critical);
16
17
my $prog_name=basename($0);
18
my $prog_revision='0.5.3';
19
20
my %errorcodes = (
21
'OK' => { 'retvalue' => 0 },
22
'WARNING' => { 'retvalue' => 1 },
23
'CRITICAL' => { 'retvalue' => 2 },
24
'UNKNOWN' => { 'retvalue' => 3 }
25
);
26
27
#
28
# Define various states and default alarm values
29
#
30
my %state = (
31
'Primary' => { 'value' => 'OK', 'type' => 'st' },
32
'Secondary' => { 'value' => 'OK', 'type' => 'st' },
33
'Unknown' => { 'value' => 'CRITICAL', 'type' => 'st' },
34
'StandAlone' => { 'value' => 'WARNING', 'type' => 'cs' },
35
'Unconnected' => { 'value' => 'CRITICAL', 'type' => 'cs' },
36
'Timeout' => { 'value' => 'CRITICAL', 'type' => 'cs' },
37
'BrokenPipe' => { 'value' => 'CRITICAL', 'type' => 'cs' },
38
'WFConnection' => { 'value' => 'CRITICAL', 'type' => 'cs' },
39
'WFReportParams' => { 'value' => 'CRITICAL', 'type' => 'cs' },
40
'Connected' => { 'value' => 'OK', 'type' => 'cs' },
41
'Unconfigured' => { 'value' => 'CRITICAL', 'type' => 'cs' },
42
# DRBD 0.6
43
'SyncingAll' => { 'value' => 'WARNING', 'type' => 'cs' },
44
'SyncingQuick' => { 'value' => 'WARNING', 'type' => 'cs' },
45
'SyncPaused' => { 'value' => 'CRITICAL', 'type' => 'cs' },
46
# DRBD 0.7
47
'WFBitMapS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
48
'WFBitMapT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
49
'SyncSource' => { 'value' => 'WARNING', 'type' => 'cs' },
50
'SyncTarget' => { 'value' => 'WARNING', 'type' => 'cs' },
51
'PausedSyncS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
52
'PausedSyncT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
53
'NetworkFailure' => { 'value' => 'CRITICAL', 'type' => 'cs' },
54
'SkippedSyncS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
55
'SkippedSyncT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
56
'Consistent' => { 'value' => 'OK', 'type' => 'ld' },
57
'Inconsistent' => { 'value' => 'CRITICAL', 'type' => 'ld' },
58
# DRBD 8.0
59
'UpToDate' => { 'value' => 'OK', 'type' => 'ds' },
60
'Consistent' => { 'value' => 'OK', 'type' => 'ds' },
61
'Negotiating' => { 'value' => 'WARNING', 'type' => 'ds' },
62
'Attaching' => { 'value' => 'WARNING', 'type' => 'ds' },
63
'Diskless' => { 'value' => 'CRITICAL', 'type' => 'ds' },
64
'Failed' => { 'value' => 'CRITICAL', 'type' => 'ds' },
65
'Outdated' => { 'value' => 'CRITICAL', 'type' => 'ds' },
66
'Inconsistent' => { 'value' => 'CRITICAL', 'type' => 'ds' },
67
'DUnknown' => { 'value' => 'CRITICAL', 'type' => 'ds' },
68
# DRBD 8.2
69
'VerifyS' => { 'value' => 'WARNING', 'type' => 'cs' },
70
'VerifyT' => { 'value' => 'WARNING', 'type' => 'cs' },
71
# DRBD 8.3
72
'Disconnecting' => { 'value' => 'WARNING', 'type' => 'cs' },
73
'ProtocolError' => { 'value' => 'CRITICAL', 'type' => 'cs' },
74
'TearDown' => { 'value' => 'WARNING', 'type' => 'cs' },
75
'StartingSyncS' => { 'value' => 'WARNING', 'type' => 'cs' },
76
'StartingSyncT' => { 'value' => 'WARNING', 'type' => 'cs' },
77
'WFSyncUUID' => { 'value' => 'WARNING', 'type' => 'cs' }
78
);
79
80
&parse_options;
81
&parse_proc;
82
&parse_drbd_devices;
83
&check_drbd_state;
84
&report_status;
85
&myexit('UNKNOWN',"$prog_name should never reach here");
86
87
sub print_usage {
88
print <<EOF
89
Usage: $prog_name [-d <All|Configured|...>] [-e expect] [-p proc] [-r role] [-o states] [-w states] [-c states] [--debug]
90
Options:
91
-d STRING [default: $drbd_devices. Example: 0,1,2 ]
92
-p STRING [default: $drbd_proc. Use '-' for stdin]
93
-e STRING [Must be this connected state. Example: Connected]
94
-r STRING [Must be this node state. Example: Primary]
95
-o STRING [Change value to OK. Example: StandAlone]
96
-w STRING [Change value to WARNING. Example: SyncingAll]
97
-c STRING [Change value to CRITICAL. Example: Inconsistent,WFConnection]
98
EOF
99
}
100
101
sub print_revision {
102
print <<EOF;
103
$prog_name $prog_revision
104
105
The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute
106
copies of the plugins under the terms of the GNU General Public License.
107
For more information about these matters, see the file named COPYING.
108
EOF
109
110
}
111
112
sub print_help {
113
&print_revision;
114
print "\n";
115
&print_usage;
116
print <<EOF;
117
118
Send email to nagios-users\@lists.sourceforge.net if you have questions
119
regarding use of this software. To submit patches or suggest improvements,
120
send email to bpoyner\@ccac.edu
121
EOF
122
exit $errorcodes{'UNKNOWN'}->{'retvalue'};
123
}
124
125
sub parse_options {
126
my ($help, $version, $debug, $ok_string, $warning_string,
127
$critical_string);
128
#
129
# Get command line options
130
#
131
GetOptions("h|help" => \$help,
132
"V|version" => \$version,
133
"d|device|devices=s" => \$drbd_devices,
134
"e|expect=s" => \$drbd_expect,
135
"p|proc=s" => \$drbd_proc,
136
"r|role=s" => \$drbd_role,
137
"o|ok=s" => \$ok_string,
138
"w|warning=s" => \$warning_string,
139
"c|critical=s" => \$critical_string,
140
"debug" => \$debug);
141
if (defined($help) && ($help ne "")) {
142
&print_help;
143
exit $errorcodes{'UNKNOWN'}->{'retvalue'};
144
}
145
if (defined($version) && ($version ne "")) {
146
&print_revision;
147
exit $errorcodes{'UNKNOWN'}->{'retvalue'};
148
}
149
if (defined($drbd_expect) && ($drbd_expect ne "")) {
150
# User requested the connected state to be very specific
151
&change_values($drbd_expect,'cs','expect','connected state');
152
}
153
if (defined($drbd_role) && ($drbd_role ne "")) {
154
# User requested the node state to be very specific
155
&change_values($drbd_role,'st','role','node state');
156
}
157
if (defined($ok_string) && ($ok_string ne "")) {
158
# User requested certain values to be OK
159
&set_values($ok_string,'OK');
160
}
161
if (defined($warning_string) && ($warning_string ne "")) {
162
# User requested certain values to be WARNING
163
&set_values($warning_string,'WARNING');
164
}
165
if (defined($critical_string) && ($critical_string ne "")) {
166
# User requested certain values to be CRITICAL
167
&set_values($critical_string,'CRITICAL');
168
}
169
if (defined($debug) && ($debug ne "")) {
170
#
171
# Debugging information
172
#
173
$debug_mode=1;
174
print STDERR "<$prog_name settings>\n";
175
print STDERR "DRBD Devices: $drbd_devices\n";
176
printf STDERR "DRBD Proc: %s\n", defined($drbd_proc)?$drbd_proc:"";
177
printf STDERR "DRBD Expect: %s\n", defined($drbd_expect)?$drbd_expect:"";
178
printf STDERR "DRBD Role: %s\n", defined($drbd_role)?$drbd_role:"";
179
my (@ok, @critical, @warning);
180
for my $key ( keys %state ) {
181
if ($state{$key}->{'value'} eq 'OK') {
182
push(@ok,$key);
183
}
184
if ($state{$key}->{'value'} eq 'WARNING') {
185
push(@warning,$key);
186
}
187
if ($state{$key}->{'value'} eq 'CRITICAL') {
188
push(@critical,$key);
189
}
190
}
191
printf STDERR "DRBD OK: %s\n", join(" ",sort(@ok));
192
printf STDERR "DRBD WARNING: %s\n", join(" ",sort(@warning));
193
printf STDERR "DRBD CRITICAL: %s\n", join(" ",sort(@critical));
194
print STDERR "</$prog_name settings>\n";
195
}
196
}
197
198
sub parse_proc {
199
#
200
# Read in contents of proc file, feed results into hashes
201
#
202
my $input;
203
if ( $drbd_proc ne "-" ) {
204
$input = "DRBD";
205
if ( ! -e $drbd_proc ) {
206
&myexit('UNKNOWN',"No such file $drbd_proc");
207
}
208
open(DRBD, "$drbd_proc") ||
209
&myexit('UNKNOWN',"Could not open $drbd_proc");
210
} else {
211
$input = "STDIN";
212
}
213
while(<$input>) {
214
if (/^version: (\d+).(\d+)/) {
215
$drbd_version = "$1.$2";
216
}
217
if (/^\s?(\d+):.* cs:(\w+)/) {
218
$cs{$1} = $2;
219
}
220
if (/^\s?(\d+):.* st:(\w+)\//) {
221
$st{$1} = $2;
222
}
223
if (/^\s?(\d+):.* ld:(\w+)/) {
224
$ld{$1} = $2;
225
}
226
if (/^\s?(\d+):.* ds:(\w+)/) {
227
$ds{$1} = $2;
228
}
229
}
230
if ( $drbd_proc ne "-" ) {
231
close(DRBD);
232
}
233
if (defined($debug_mode) && ($debug_mode == 1)) {
234
#
235
# Debugging information
236
#
237
print STDERR "<$prog_name devices found>\n";
238
for my $key ( sort keys %cs ) {
239
printf STDERR "Found Device $key $cs{$key}%s%s%s\n", defined($st{$key})?" $st{$key}":"", defined($ld{$key})?" $ld{$key}":"", defined($ds{$key})?" $ds{$key}":"";
240
}
241
print STDERR "</$prog_name devices found>\n";
242
}
243
}
244
245
sub parse_drbd_devices {
246
#
247
# Determine which DRBD devices to monitor
248
#
249
my @devices;
250
if ($drbd_devices =~ /^all$/i) {
251
for my $device ( keys %cs ) {
252
push(@devices,$device);
253
}
254
} elsif ($drbd_devices =~ /^configured$/i) {
255
for my $device ( keys %cs ) {
256
next if ($cs{$device} eq "Unconfigured");
257
push(@devices,$device);
258
}
259
} else {
260
@devices = split(/,/,$drbd_devices);
261
}
262
foreach my $device (@devices) {
263
if (!(defined($cs{$device}))) {
264
&myexit('UNKNOWN',"Could not find device $device");
265
}
266
$check{$device} = 1;
267
}
268
if (int(keys %check) == 0) {
269
&myexit('UNKNOWN',"No configured devices found");
270
}
271
if (defined($debug_mode) && ($debug_mode == 1)) {
272
#
273
# Debugging information
274
#
275
print STDERR "<$prog_name devices to check>\n";
276
for my $key ( sort keys %check ) {
277
printf STDERR "Checking enabled for device $key\n";
278
}
279
print STDERR "</$prog_name devices to check>\n";
280
}
281
}
282
283
sub check_drbd_state {
284
for my $drbd_device ( sort keys %check ) {
285
if ((defined($drbd_version)) && ($drbd_version >= '8.0')) {
286
#
287
# We're dealing with version 8.0 or greater
288
# Set data state
289
#
290
if ((defined($ds{$drbd_device})) &&
291
(defined($state{$ds{$drbd_device}}))) {
292
$state{$ds{$drbd_device}}->{$drbd_device}->{'level'} = 1;
293
} elsif (defined($ds{$drbd_device})) {
294
&myexit('CRITICAL',"Data state unknown value '$ds{$drbd_device}' for device $drbd_device");
295
}
296
}
297
if ((defined($drbd_version)) && ($drbd_version == '0.7')) {
298
#
299
# We're dealing with version 0.7
300
# Set local data consistency
301
#
302
if ((defined($ld{$drbd_device})) &&
303
(defined($state{$ld{$drbd_device}}))) {
304
$state{$ld{$drbd_device}}->{$drbd_device}->{'level'} = 1;
305
} elsif (defined($ld{$drbd_device})) {
306
&myexit('CRITICAL',"Local data consistency unknown value '$ld{$drbd_device}' for device $drbd_device");
307
}
308
}
309
#
310
# Check for a state value (Primary, Secondary, etc)
311
#
312
if ((defined($st{$drbd_device})) &&
313
(defined($state{$st{$drbd_device}}))) {
314
$state{$st{$drbd_device}}->{$drbd_device}->{'level'} = 1;
315
} elsif (defined($st{$drbd_device})) {
316
&myexit('CRITICAL',"Node state unknown value '$st{$drbd_device}' for device $drbd_device");
317
}
318
#
319
# Check for a connected state value (Connected, StandAlone, etc)
320
#
321
if (defined($state{$cs{$drbd_device}})) {
322
$state{$cs{$drbd_device}}->{$drbd_device}->{'level'} = 1;
323
} else {
324
&myexit('CRITICAL',"Connection state unknown value '$cs{$drbd_device}' for device $drbd_device");
325
}
326
#
327
# Debugging information
328
#
329
if (defined($debug_mode) && ($debug_mode == 1)) {
330
print STDERR "<$prog_name device $drbd_device status>\n";
331
for my $key ( keys %state ) {
332
if (defined($state{$key}->{$drbd_device}->{'level'})) {
333
print STDERR "$key $state{$key}->{'value'}\n";
334
}
335
}
336
print STDERR "</$prog_name device $drbd_device status>\n";
337
}
338
#
339
# Determine if any values are CRITICAL or WARNING
340
#
341
for my $key ( keys %state ) {
342
if (defined($state{$key}->{$drbd_device}->{'level'})) {
343
if ($state{$key}->{'value'} eq "CRITICAL") {
344
$critical{$drbd_device} = 1;
345
}
346
if ($state{$key}->{'value'} eq "WARNING") {
347
$warning{$drbd_device} = 1;
348
}
349
}
350
}
351
}
352
}
353
354
sub report_status {
355
my $message;
356
my $critical_count=int(keys %critical);
357
my $warning_count=int(keys %warning);
358
if ($critical_count > 0) {
359
#
360
# We found a CRITICAL situation
361
#
362
my $i = 0;
363
for my $device (sort keys %critical) {
364
$message.=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
365
$i++;
366
if ($i != $critical_count) {
367
$message.=", ";
368
}
369
}
370
&myexit('CRITICAL',$message);
371
} elsif ($warning_count > 0) {
372
#
373
# We found a WARNING situation
374
#
375
my $i = 0;
376
for my $device (sort keys %warning) {
377
$message.=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
378
$i++;
379
if ($i != $warning_count) {
380
$message.=", ";
381
}
382
}
383
&myexit('WARNING',$message);
384
} else {
385
#
386
# Everything checks out OK
387
#
388
my $device_count=int(keys %check);
389
if ($device_count == 1) {
390
for my $device ( sort keys %check ) {
391
$message=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
392
}
393
} else {
394
my $i = 0;
395
for my $device ( sort keys %check ) {
396
$message.=sprintf("Dev %d %0.3s%0.3s%0.3s%0.3s", $device,defined($st{$device})?"$st{$device}":"",$cs{$device},defined($ld{$device})?"$ld{$device}":"",defined($ds{$device})?"$ds{$device}":"");
397
$i++;
398
if ($i != $device_count) {
399
$message.=", ";
400
}
401
}
402
}
403
&myexit('OK',$message);
404
}
405
}
406
407
sub set_values {
408
#
409
# Set item to value requested
410
#
411
my ($items,$value) = @_;
412
my @items = split(/,/,$items);
413
foreach my $item (@items) {
414
if (defined($state{$item})) {
415
$state{$item}->{'value'} = "$value";
416
} else {
417
print STDERR "State '$item' not found\n";
418
}
419
}
420
}
421
422
sub change_values {
423
#
424
# Look for all values of a given type, set requested value to OK
425
# and all other values to CRITICAL
426
#
427
my ($argument,$type,$error1,$error2) = @_;
428
if ((defined($state{$argument})) &&
429
($state{$argument}->{'type'} eq "$type")) {
430
for my $key ( keys %state ) {
431
if ($state{$key}->{'type'} eq "$type") {
432
if ($key eq $argument) {
433
&set_values($argument,'OK');
434
} else {
435
&set_values($key,'CRITICAL');
436
}
437
}
438
}
439
} else {
440
&myexit('UNKNOWN',"$error1 option only works for $error2");
441
}
442
}
443
444
sub myexit {
445
#
446
# Print error message and exit
447
#
448
my ($error, $message) = @_;
449
if (!(defined($errorcodes{$error}))) {
450
printf STDERR "Error code $error not known\n";
451
print "DRBD UNKNOWN: $message\n";
452
exit $errorcodes{'UNKNOWN'}->{'retvalue'};
453
}
454
print "DRBD $error: $message\n";
455
exit $errorcodes{$error}->{'retvalue'};
456
}
457