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

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