-2

The below is driving me crazy.

I submit the whole function for clarity. The aim here is to log an error every time a Linux mirror sub-device is faulty OR when a sub-device has been removed. I just need to have one message every time. mdadm commands output always displays a line with removed and a line with faulty if the sub-device has not been completely removed from the mirror and is in faulted state. I just want to log only the sub-device faulty part in this case and not the removed one.

One the device has been removed from the mirror, there is no faulty error any more, but only removed. In this case I need to log the removed error.

For that I use a variable $myfaulty and parse the mdadm --detail $md_dev output. The problem is that the part of the code that comes first is evaluated second.

The below code comes first:

elsif ($subdevice_status =~ /faulty/) {
_msg("ERROR: MD device $device status $device_status, sub-device status $subdevice_status " );
_mylog('err', "ERROR: faulty MD $device $device_status: sub-device $subdevice ($subdevice_role): status $subdevice_status " );
  $myfaulty = 1;

And this comes second:

elsif ($subdevice_status =~ /removed/ && $myfaulty != 1 ) {
 _msg("ERROR: MD device $device status $device_status, sub-device status $subdevice_status " );
 printf("The removed part: $myfaulty, $device, $raid_type \n");
 _mylog('err', "ERROR: MD device $device status $device_status, sub-device $subdevice_status " );

The $myfaulty variable evaluation happens first on the second block of code and then on the first.

Any ideas?

Thanks, George

Sub code

# checks all MD volumes it finds on the system
sub check_md() {
my $MDADMCMD = "";
my $device = "";
my $subdevice = "";
my $device_status = "";
my $subdevice_status = "";
my $raid_type = "";
my $subdevice_role = "";
my $raid_count = 0;
my $lines = 0;
my $myfaulty = 0;

    foreach(@mdadm_paths) {
            if( -e $_ ) { $MDADMCMD = $_; _debug("using mdadm in $MDADMCMD"); last; }
    }
    if($MDADMCMD eq "") { _msg("MD not configured on this system (mdadm not found) - "); return; }
    open MDSCAN, "-|", "$MDADMCMD --detail --scan --verbose 2>&1" || die "can't run: $!";
    while(<MDSCAN>) {
            $lines++;
            if($_ =~ /^ARRAY/) {
                    $_ =~ /^ARRAY\s+(\S+)\s+level=(\S+)\s+/;
                    $device = $1;
                    $raid_type = $2;
                    $raid_count++;
                    _debug("found MD device $device, raid-level $raid_type");
            open MDDETAIL, "-|", "$MDADMCMD --detail $device" || die "can't run: $!"; while(<MDDETAIL>) {
    printf($_);
                            if($_ =~ /\s+State\s+:\s+(.+)$/) { # md device status
                                    $device_status = $1;
                                    chomp($device_status);
                                    _debug("device status: $device_status");


                                    if($device_status !~ /clean$/) {
                                            change_status("CRITICAL");
                                            $md_status = "CRITICAL";

                            }

                             if($_ =~ /^\s+(\d+|-)\s+(\d+|-)\s+(\d+|-)\s+(\d+|-)\s+(\w+)\s+(\w+)\s+(\S+)\s*$/) {
                                    $subdevice_status = $5; $subdevice_role = $6; $subdevice = $7;
                                    _debug("device:$device - subdevice:$subdevice - role:$subdevice_role - status:$subdevice_status");
                                    if($subdevice_status !~ /active/) {
                                            change_status("CRITICAL");
                                            $md_status = "CRITICAL";
                                            _msg("MD $device, sub-device $subdevice ($subdevice_role): status $subdevice_status - ");
                                            if ($subdevice_role =~ /rebuilding/) {
                                            _mylog('warning', "WARNING: MD $device $device_status: sub-device $subdevice ($subdevice_role): status $subdevice_status " );
                                             }
                                            elsif ($subdevice_status =~ /faulty/) {
                                            _msg("ERROR: MD device $device status $device_status, sub-device status $subdevice_status " );
                                            _mylog('err', "ERROR: faulty MD $device $device_status: sub-device $subdevice ($subdevice_role): status $subdevice_status " );
                                            $myfaulty = 1;
                                            printf("Faulty is here:  $myfaulty, $subdevice_status, $raid_type \n");
                                            }
                                            elsif ($subdevice_status =~ /removed/ && $myfaulty != 1 ) {
                                                     _msg("ERROR: MD device $device status $device_status, sub-device status $subdevice_status " );
                                                     printf("The removed part: $myfaulty, $device, $raid_type \n");
                                                     _mylog('err', "ERROR: MD device $device status $device_status, sub-device $subdevice_status " );

                                            }
                                            else {
                                            _msg("MD $device, sub-device $subdevice ($subdevice_role): status $subdevice_status - ");
                                            _mylog('err', "ERROR: after faulty MD $device $device_status: sub-device $subdevice ($subdevice_role): status $subdevice_status " );
                                            }
                                    }
                                            else { _verbosemsg("MD $device, sub-device $subdevice ($subdevice_role): status OK - "); }
                             # Need to also catch subdevices that have been removed and don't show up anymore.
                    }
                    if ($_ =~ /^\s+(\d+|-)\s+(\d+|-)\s+(\d+|-)\s+(\d+|-)\s+(\w+)\s*$/) {
                                   $subdevice_status = $5;
                                     _debug("device:$device - subdevice:$subdevice - role:$subdevice_role - status:$subdevice_status");

                                            printf("The removed part: $myfaulty, $device, $raid_type \n");
                                    if ($subdevice_status =~ m/removed/ && $myfaulty != 1 ) {
                                            _msg("ERROR: MD device $device status $device_status, sub-device status $subdevice_status " );
                                            printf("The removed part: $myfaulty, $device, $raid_type \n");
                                            _mylog('err', "ERROR: MD device $device status $device_status, sub-device $subdevice_status " );
                                            }
                            }
                    } #while(<MDDETAIL>)
                    close(MDDETAIL);
            }
    }
    close(MDSCAN);
    # no md devices found, but command output wasn't empty
    if($raid_count == 0 && $lines > 0) { _msg("MD status is UNKNOWN (can't get configuration info) - "); }
    elsif($raid_count == 0) { _msg("MD not configured on this system - "); }
    elsif($md_status eq "OK" && not defined $verbOutput) { _msg("MD Status is OK - ");  }  }

mdadm --detail output

/dev/md0:
    Version : 0.90
Creation Time : Mon Mar  4 12:53:19 2013
 Raid Level : raid1
 Array Size : 521984 (509.84 MiB 534.51 MB)
Used Dev Size : 521984 (509.84 MiB 534.51 MB)
 Raid Devices : 2
Total Devices : 2
Preferred Minor : 0
Persistence : Superblock is persistent

Update Time : Thu Jul  4 16:27:46 2013
      State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 1
Spare Devices : 0

       UUID : 3a3bd078:31678889:9485a7cf:e1283d32
     Events : 0.438

Number   Major   Minor   RaidDevice State
   0       0        0        0      removed
   1       8       33        1      active sync   /dev/sdc1

   2       8       17        -      faulty spare   /dev/sdb1
4

2 回答 2

1

我试图查看您的代码,但它非常冗长,并且不适合我的计算机屏幕,因此我想向您展示您可以做什么来解析该特定输入。

不过,首先,这是一个粗心的陷阱:

open MDDETAIL, "-|", "$MDADMCMD --detail $device" || die "can't run: $!";

如果您查看perldoc perlop,您会注意到优先级表中的优先||级高于,(逗号)。这意味着上面的陈述确实意味着:

open MDDETAIL, "-|", 
    ("$MDADMCMD --detail $device" || die "can't run: $!");

或者,换句话说,for 的第三个参数open要么变成一个字符串,要么变成一个die语句。因为这个字符串不是空的,所以它总是正确的(毕竟它是一个常数),而且由于||简短的 curcuts,这个die语句永远不会发生。即使可以,它也不再与open命令的返回值相关联。这是你应该做的:

open(my $fh, "<", $file) || die $!;     # use parentheses to override precedence
open my $fh, "<", $file  or die $!;     # use "or" which has lower precedence

主要问题

解析你的输入并不难,只是有点挑剔。解析后,您可以轻松提取所需的部分。因此,与其编写极其复​​杂的循环和嵌套的 if 语句,不如先将文本分开。

use strict;
use warnings;
use Data::Dumper;

my %data;
my $input;
{
    local $/;                              # disable input record separator
    $input = <DATA>;                       # read entire input into one string
}
my ($num) = $input =~ /\n\n(Number.*)/s;   # extract table part
$input =~ s/\n\n(Number.*)//s;             # remove from keys/values
my @vals = grep /\S/, split /\n+/, $input;
my $dev = shift @vals;
$data{Device} = $dev;                      # extract dev name
for (@vals) {
    if (/^\s*([^:]+)\s*:(.*)/) {
        $data{$1} = $2;                # parse and store the key/values
    } else { warn "Bad data: $_"; }
}
my @nums = split /\n+/, $num;
my $header = shift @nums;                  # remove header
for (@nums) {
    s/^\s+//;                              # remove leading whitespace
    my @items = split /\s{2,}/;            # split on 2 or more whitespace
    my $state = $items[4];
    my $dev = $items[5] // "N/A";          # use fields as required
    print "Device: $dev, State: $state\n";
    # do stuff
}
print Dumper \%data;                       # this is the key/values we stored

# below is sample input
__DATA__
/dev/md0:
    Version : 0.90
Creation Time : Mon Mar  4 12:53:19 2013
 Raid Level : raid1
 Array Size : 521984 (509.84 MiB 534.51 MB)
Used Dev Size : 521984 (509.84 MiB 534.51 MB)
 Raid Devices : 2
Total Devices : 2
Preferred Minor : 0
Persistence : Superblock is persistent

Update Time : Thu Jul  4 16:27:46 2013
      State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 1
Spare Devices : 0

       UUID : 3a3bd078:31678889:9485a7cf:e1283d32
     Events : 0.438

Number   Major   Minor   RaidDevice State
   0       0        0        0      removed
   1       8       33        1      active sync   /dev/sdc1
   2       8       17        -      faulty spare   /dev/sdb1

输出:

Device: N/A, State: removed
Device: /dev/sdc1, State: active sync
Device: /dev/sdb1, State: faulty spare
$VAR1 = {
          'Events ' => ' 0.438',
          'UUID ' => ' 3a3bd078:31678889:9485a7cf:e1283d32',
          'Persistence ' => ' Superblock is persistent',
          'Active Devices ' => ' 1',
          'Array Size ' => ' 521984 (509.84 MiB 534.51 MB)',
          'Spare Devices ' => ' 0',
          'Device' => '/dev/md0:',
          'State ' => ' clean, degraded',
          'Total Devices ' => ' 2',
          'Preferred Minor ' => ' 0',
          'Creation Time ' => ' Mon Mar  4 12:53:19 2013',
          'Used Dev Size ' => ' 521984 (509.84 MiB 534.51 MB)',
          'Failed Devices ' => ' 1',
          'Version ' => ' 0.90',
          'Raid Devices ' => ' 2',
          'Raid Level ' => ' raid1',
          'Working Devices ' => ' 1',
          'Update Time ' => ' Thu Jul  4 16:27:46 2013'
        };
于 2013-07-05T11:33:25.477 回答
0

mdadm --detail output问题似乎是您正在记录输出,因为您解析每一行但在决定输出什么之前您需要了解所有行。

您需要在文件解析循环结束后重构检查 $subdevice_status 的那段代码,然后您可以检查您是否被删除并且 $myfaulty 不正确。您需要将更多信息存储在变量中,而不是直接将它们记录下来。

于 2013-07-05T12:33:25.150 回答