PatchInventory: check_drbd

File check_drbd, 14.0 kB (added by admin, 3 years ago)

check_drbd

Line 
1#!/usr/bin/perl -w
2
3####################################################
4# check_drbd v0.5.3                                #
5# by Brandon Lee Poyner    bpoyner / CCAC.edu      #
6####################################################
7
8use strict;
9use File::Basename;
10use Getopt::Long;
11
12my $drbd_proc='/proc/drbd';
13my $drbd_devices=0;
14my ($drbd_expect, $drbd_role, $drbd_version, $debug_mode); 
15my (%options, %cs, %st, %ld, %ds, %check, %warning, %critical);
16
17my $prog_name=basename($0);
18my $prog_revision='0.5.3';
19
20my %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#
30my %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' => 'OK', '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
87sub print_usage {
88        print <<EOF
89Usage: $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]
98EOF
99}
100
101sub print_revision {
102        print <<EOF;
103$prog_name $prog_revision
104
105The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute
106copies of the plugins under the terms of the GNU General Public License.
107For more information about these matters, see the file named COPYING.
108EOF
109
110}
111
112sub print_help {
113        &print_revision;
114        print "\n";
115        &print_usage;
116        print <<EOF;
117
118Send email to nagios-users\@lists.sourceforge.net if you have questions
119regarding use of this software. To submit patches or suggest improvements,
120send email to bpoyner\@ccac.edu
121EOF
122        exit $errorcodes{'UNKNOWN'}->{'retvalue'};
123}
124
125sub 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
198sub 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
245sub 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('OK',"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
283sub 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
354sub 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
407sub 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
422sub 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
444sub 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}