added support for cluster disks, added --terse

This commit is contained in:
Patrick Van der Veken 2017-12-12 10:50:29 +01:00
parent 7a170b92c2
commit 821a1b245a

View File

@ -31,6 +31,7 @@ use warnings;
use POSIX qw(uname);
use Getopt::Long;
use Pod::Usage;
use Data::Dumper;
$|++;
@ -38,10 +39,11 @@ $|++;
# DATA structures
#******************************************************************************
my ($os, $version, $footer);
my ($os, $version, $footer, $warning);
my $warn_devices = 500;
my %options;
my (@pvol, @vgdisplay);
my (@pvol, @cvol, @vgdisplay);
my %cdsf;
#******************************************************************************
# SUBroutines
@ -50,26 +52,82 @@ my (@pvol, @vgdisplay);
sub parse_pvols {
my @pvol = @_;
my @pvdisplay;
my $pv_command;
my %pvdisplay;
my @dsf;
unless (@pvol) {
print "-- no disks found --\n";
return;
}
# collect DSF/cDSF & pvol info
foreach my $pvol (@pvol) {
my $pv_lvm = 1;
my (@dsf_data, @cdsf_data);
my ($dsf, $cdsf, $is_cdsf) = ("","",0);
chomp ($pvol);
@pvdisplay = `/usr/sbin/pvdisplay -F /dev/disk/${pvol} 2>&1`;
$pv_lvm = 0 if ($?) and (grep (/cannot display physical volume/i, @pvdisplay));
# check for DSF or cDSF?
if ($pvol =~ m/cdisk/) {
$pvol =~ s#cdisk/##;
$is_cdsf = 1;
# we have the cDSF, get the DSF (should only be 1!)
@dsf_data = grep (/rcdisk\/${pvol}:/, @cvol);
($dsf) = (split (/:/, $dsf_data[0]))[1];
$dsf =~ s#/dev/rdisk/## if (defined ($dsf));
# save the cDSF
push (@{$cdsf{$dsf}}, $pvol);
} else {
# we have the DSF, get the cDSF (could be >1)
@cdsf_data = grep (/rdisk\/${pvol}:/, @cvol);
($dsf = $pvol) =~ s#disk/## if (defined ($dsf));
# loop over pvdisplay
if ($pv_lvm) {
# set cDSF flag if we found cDSFs
$is_cdsf = 1 if (@cdsf_data);
foreach my $pv_entry (@pvdisplay) {
# loop over cDSF data
foreach my $cdsf_data (@cdsf_data) {
($cdsf) = (split (/:/, $cdsf_data))[0];
$cdsf =~ s#/dev/rcdisk/##;
# save the cDSF
push (@{$cdsf{$dsf}}, $cdsf) if (defined ($cdsf));
}
}
# pvdisplay on DSF/cDSF (must be correct one!) but record it under $dsf
# no error handling here, error indicates: inactive/non-LVM stuff
if ($is_cdsf) {
# get info of the first cDSF
@{$pvdisplay{$dsf}} = `/usr/sbin/pvdisplay -F /dev/cdisk/@{$cdsf{$dsf}}[0] 2>/dev/null`;
} else {
@{$pvdisplay{$dsf}} = `/usr/sbin/pvdisplay -F /dev/disk/${dsf} 2>/dev/null`;
}
push (@dsf, $dsf);
}
# display pvol data (sorted by their device number: diskYYYY)
foreach my $dsf (sort { substr($a, 4) <=> substr($b, 4) } (@dsf)) {
chomp ($dsf);
my ($cdsf, $cdsf_bit) = ("","");
# make cDSF bit
if (defined (@{$cdsf{$dsf}})) {
# display only the first cDSF! (in case of multiples)
$cdsf = @{$cdsf{$dsf}}[0];
$cdsf_bit = "(".scalar (@{$cdsf{$dsf}}).")";
} else {
$cdsf = "n/a";
}
if (@{$pvdisplay{$dsf}}) {
# check for PV data
foreach my $pv_entry (@{$pvdisplay{$dsf}}) {
my ($vg_name, $pv_status)= ("","");
my ($pv_total_pe, $pv_size_pe, $pv_free_pe, $pv_stale_pe) = (0,0,0,0);
@ -94,18 +152,23 @@ sub parse_pvols {
$pv_free /= 1024 unless ($options{'size'} =~ /MB/i);
# report data
printf STDOUT ("%-20s %-12s %-15s %-7d %-8d %-8d %-8d\n",
"/dev/disk/${pvol}",
${vg_name},
${pv_status},
${pv_size_pe},
${pv_size},
${pv_free},
${pv_stale_pe})
printf STDOUT ("%-12s %-10s %-4s %-25s %-20s %-7d %-8d %-8d %-8d\n",
$dsf,
$cdsf,
$cdsf_bit,
$vg_name,
$pv_status,
$pv_size_pe,
$pv_size,
$pv_free,
$pv_stale_pe)
}
} else {
unless ($options{'active'}) {
printf STDOUT ("%-20s %-12s %-15s\n", "/dev/disk/${pvol}",
printf STDOUT ("%-12s %-10s %-4s %-25s %-20s\n",
$dsf,
$cdsf,
$cdsf_bit,
"n/a",
"not active/not LVM");
}
@ -113,6 +176,22 @@ sub parse_pvols {
}
}
sub print_header {
unless ($options{'terse'}) {
if (scalar (@pvol) > $warn_devices) {
$warning = qq{
WARNING: You have more than $warn_devices disk devices on your system. Collecting the PV information will take some time...
};
print STDOUT "$warning";
}
printf STDOUT ("\n%-12s %-10s %-4s %-25s %-20s %-7s %-8s %-8s %-8s\n",
"PV", "cDSF", "(#)", "VG", "Status", "PE Size", "PV Size", "PV Free", "Stale PE");
}
}
#******************************************************************************
# MAIN routine
@ -132,6 +211,7 @@ if ( @ARGV > 0 ) {
size|s=s
vg|g=s
active|a
terse|t
));
}
# check options
@ -142,36 +222,54 @@ if ($options{'help'}) {
unless ($options{'size'}) {
$options{'size'} = 'GB';
};
if ($options{'vg'}) {
if ($options{'vg'} =~ m#/dev#) {
print STDERR "ERROR: do not specify your VG with '/dev/...'. Only use the short VG name\n\n";
exit (0);
}
# force --active off
delete $options{'active'};
};
# print header
printf STDOUT ("\n%-20s %-12s %-15s %-7s %-8s %-8s %-8s\n",
"PV", "VG", "Status", "PE Size", "PV Size", "PV Free", "Stale PE");
# fetch cDSF map
@cvol = `/usr/sbin/ioscan -kFN -m cluster_dsf 2>/dev/null`;
die "ERROR: could not retrieve cDSF info" if ($?);
# fetch PVOLs (non-boot)
if ($options{'vg'}) {
@pvol = `/usr/sbin/vgdisplay -vF "/dev/${options{'vg'}}" 2>/dev/null | grep "^pv_name" | cut -f1 -d':' | cut -f2 -d'=' | cut -f4 -d '/'`;
die "failed to execute: $!" if ($?);
# pvols can be cluster-wide or regular disks here! (output: cdisk/diskXXXX or disk/diskYYYY)
@pvol = `/usr/sbin/vgdisplay -vF "/dev/${options{'vg'}}" 2>/dev/null | grep "^pv_name" | cut -f1 -d':' | cut -f2 -d'=' | cut -f3-4 -d '/'`;
unless (@pvol) { die "ERROR: could not retrieve VG info for ${options{'vg'}}" };
print_header;
parse_pvols (@pvol);
} else {
# output: diskYYYY
@pvol = `/usr/sbin/ioscan -kFN -C disk 2>/dev/null | cut -f9,13 -d':' | tr -d ':'`;
die "failed to execute: $!" if ($?);
die "ERROR: could not retrieve ioscan info" if ($?);
print_header;
parse_pvols (@pvol);
# fetch PVOLs (boot)
print "\n-- Boot disk(s):\n";
# fetch PVOLs (boot); output: diskYYYY
unless ($options{'terse'}) { print "\n-- Boot disk(s):\n"; }
@pvol = `/usr/sbin/lvlnboot -v 2>/dev/null | grep 'Boot Disk' | awk '{ print \$1 }' | cut -f4 -d '/'`;
die "failed to execute: $!" if ($?);
die "ERROR: could not retrieve boot info" if ($?);
parse_pvols (@pvol);
}
# footer
unless ($options{'terse'}) {
$footer = qq{
Note 1: 'PE Size' values are expressed in MB
Note 2: 'PV Size' & 'PV Free' values are expressed in GB by default (see --help)
Note 3: cDSF: only the first cluster-wide device is shown in case of multiples. The number of cDSF is displayed in
parentheses following the cDSF name.
Note 3: more detailed information can be obtained by running the pvdisplay(1M), vgdisplay(1M), lvdisplay(1M) commands
};
print STDOUT $footer;
}
exit (0);
@ -195,6 +293,7 @@ pvs.pl - Show physical volume information in a terse way (Linux style).
[(-g|--vg)=<vg_name>]
[(-s|--size)=<MB|GB>]
[(-a|--active)]
[(-t|--terse)]
=head1 OPTIONS
@ -206,22 +305,32 @@ S< >Show the help page.
=item -a | --active
S< >Hide non-active and non-LVM disks
S< >Hide non-active and non-LVM disks. Cannot be used in conjunction with --vg.
=item -g | --vg
S< >Display physical volumes for a specific volume group. Volume group name should be specified without the "/dev/" prefix
S< >Display physical volumes for a specific volume group. Volume group name should be specified without the "/dev/" prefix.
=item -s | --size
S< >Show physical volume size in MB or GB (default is GB).
=item -t | --terse
S< >Do not show header and footer information.
=head1 NOTE
Collecting & displaying the data might take a considerable amount of time depending
on the amount of devices present on the system.
=head1 AUTHOR
(c) KUDOS BVBA - Patrick Van der Veken
=head1 history
@(#) 2016-04-12: VRF 1.0.0: first version [Patrick Van der Veken]
@(#) 2016-04-27: VRF 1.0.1: small fixes [Patrick Van der Veken]
@(#) 2016-04-27: VRF 1.1.0: show all PVOLs & option --active added [Patrick Van der Veken]
@(#) 2016-04-12: first version [Patrick Van der Veken]
@(#) 2016-04-27: small fixes [Patrick Van der Veken]
@(#) 2016-04-27: show all PVOLs & option --active added [Patrick Van der Veken]
@(#) 2017-12-12: added support for cluster disks, added --terse [Patrick Van der Veken]