以下让我发疯。
为了清晰起见,我提交了整个功能。这里的目的是在每次Linux镜像子设备出现故障或删除子设备时记录错误。我只需要每次都有一条消息。如果子设备尚未从镜像中完全移除并且处于故障状态,则mdadm命令输出始终显示已删除的行和有故障的行。我只想在这种情况下只记录子设备故障部分而不是删除部分。
设备已从镜像中移除,不再出现错误,但仅删除了。在这种情况下,我需要记录删除的错误。
为此,我使用变量$myfaulty
并解析mdadm --detail $md_dev
输出。
问题是第一个出现的代码部分是第二个。
以下代码首先出现:
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;
这是第二个:
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 " );
$ myfaulty变量评估首先发生在第二个代码块上,然后发生在第一个代码块上。
有什么想法吗?
谢谢, 乔治
# 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 - "); } }
/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
答案 0 :(得分:1)
我试图查看你的代码,但它相当痛苦,并且不适合我的电脑屏幕,所以我想告诉你你可以做什么而不是解析那个特定的输入。
首先,这是一个疏忽的陷阱:
open MDDETAIL, "-|", "$MDADMCMD --detail $device" || die "can't run: $!";
如果查看perldoc perlop,您会在优先级表中注意到||
的优先级高于,
(逗号)。这意味着上述陈述的确意味着:
open MDDETAIL, "-|",
("$MDADMCMD --detail $device" || die "can't run: $!");
或者,换句话说,open
的第三个参数变为字符串或die
语句。因为这个字符串不是空的,所以它总是为真(毕竟它是一个常量),并且由于||
短的curcuits,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'
};
答案 1 :(得分:0)
问题似乎是你正在记录你的输出,因为你在决定要输出什么之前解析每一行但你需要知道mdadm --detail output
中的所有行。
您需要重构那些在文件解析循环结束后检查$ subdevice_status的代码,这样您就可以检查是否已删除AND $ myfaulty不正确。您需要在变量中存储更多信息,而不是直接记录它们。