added support for cluster disks, added --terse
This commit is contained in:
parent
7a170b92c2
commit
821a1b245a
279
lx-lvm/pvs.pl
279
lx-lvm/pvs.pl
@ -14,7 +14,7 @@
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
|
||||
#******************************************************************************
|
||||
# This script will display HP-UX LVM information in Linux style
|
||||
#
|
||||
#
|
||||
# Based on https://jreypo.wordpress.com/2010/02/16/linux-lvm-commands-in-hp-ux/
|
||||
#
|
||||
# @(#) HISTORY: see perldoc 'pvs.pl'
|
||||
@ -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,67 +52,144 @@ 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;
|
||||
}
|
||||
|
||||
foreach my $pvol (@pvol) {
|
||||
unless (@pvol) {
|
||||
print "-- no disks found --\n";
|
||||
return;
|
||||
}
|
||||
|
||||
my $pv_lvm = 1;
|
||||
|
||||
chomp ($pvol);
|
||||
|
||||
@pvdisplay = `/usr/sbin/pvdisplay -F /dev/disk/${pvol} 2>&1`;
|
||||
$pv_lvm = 0 if ($?) and (grep (/cannot display physical volume/i, @pvdisplay));
|
||||
|
||||
# loop over pvdisplay
|
||||
if ($pv_lvm) {
|
||||
|
||||
foreach my $pv_entry (@pvdisplay) {
|
||||
|
||||
my ($vg_name, $pv_status)= ("","");
|
||||
my ($pv_total_pe, $pv_size_pe, $pv_free_pe, $pv_stale_pe) = (0,0,0,0);
|
||||
my ($pv_size, $pv_free) = (0,0);
|
||||
|
||||
my @pv_data = split (/:/, $pv_entry);
|
||||
# collect DSF/cDSF & pvol info
|
||||
foreach my $pvol (@pvol) {
|
||||
|
||||
# loop over PVOL data
|
||||
foreach my $pv_field (@pv_data) {
|
||||
my (@dsf_data, @cdsf_data);
|
||||
my ($dsf, $cdsf, $is_cdsf) = ("","",0);
|
||||
|
||||
$vg_name = $1 if ($pv_field =~ m%^vg_name=/dev/(.*)%);
|
||||
$pv_status = $1 if ($pv_field =~ m%^pv_status=(.*)%);
|
||||
$pv_total_pe = $1 if ($pv_field =~ m%^total_pe=(.*)%);
|
||||
$pv_size_pe = $1 if ($pv_field =~ m%^pe_size=(.*)%);
|
||||
$pv_free_pe = $1 if ($pv_field =~ m%^free_pe=(.*)%);
|
||||
$pv_stale_pe = $1 if ($pv_field =~ m%^stale_pe=(.*)%);
|
||||
}
|
||||
# calculate sizes
|
||||
$pv_size = $pv_total_pe * $pv_size_pe;
|
||||
$pv_size /= 1024 unless ($options{'size'} =~ /MB/i);
|
||||
$pv_free = $pv_free_pe * $pv_size_pe;
|
||||
$pv_free /= 1024 unless ($options{'size'} =~ /MB/i);
|
||||
chomp ($pvol);
|
||||
|
||||
# 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})
|
||||
}
|
||||
} else {
|
||||
unless ($options{'active'}) {
|
||||
printf STDOUT ("%-20s %-12s %-15s\n", "/dev/disk/${pvol}",
|
||||
"n/a",
|
||||
"not active/not LVM");
|
||||
}
|
||||
}
|
||||
}
|
||||
# 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));
|
||||
|
||||
# set cDSF flag if we found cDSFs
|
||||
$is_cdsf = 1 if (@cdsf_data);
|
||||
|
||||
# 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);
|
||||
my ($pv_size, $pv_free) = (0,0);
|
||||
|
||||
my @pv_data = split (/:/, $pv_entry);
|
||||
|
||||
# loop over PVOL data
|
||||
foreach my $pv_field (@pv_data) {
|
||||
|
||||
$vg_name = $1 if ($pv_field =~ m%^vg_name=/dev/(.*)%);
|
||||
$pv_status = $1 if ($pv_field =~ m%^pv_status=(.*)%);
|
||||
$pv_total_pe = $1 if ($pv_field =~ m%^total_pe=(.*)%);
|
||||
$pv_size_pe = $1 if ($pv_field =~ m%^pe_size=(.*)%);
|
||||
$pv_free_pe = $1 if ($pv_field =~ m%^free_pe=(.*)%);
|
||||
$pv_stale_pe = $1 if ($pv_field =~ m%^stale_pe=(.*)%);
|
||||
}
|
||||
# calculate sizes
|
||||
$pv_size = $pv_total_pe * $pv_size_pe;
|
||||
$pv_size /= 1024 unless ($options{'size'} =~ /MB/i);
|
||||
$pv_free = $pv_free_pe * $pv_size_pe;
|
||||
$pv_free /= 1024 unless ($options{'size'} =~ /MB/i);
|
||||
|
||||
# report data
|
||||
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 ("%-12s %-10s %-4s %-25s %-20s\n",
|
||||
$dsf,
|
||||
$cdsf,
|
||||
$cdsf_bit,
|
||||
"n/a",
|
||||
"not active/not LVM");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -131,7 +210,8 @@ if ( @ARGV > 0 ) {
|
||||
help|h|?
|
||||
size|s=s
|
||||
vg|g=s
|
||||
active|a
|
||||
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 ($?);
|
||||
parse_pvols (@pvol);
|
||||
# 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 {
|
||||
@pvol = `/usr/sbin/ioscan -kFN -C disk 2>/dev/null | cut -f9,13 -d':' | tr -d ':'`;
|
||||
die "failed to execute: $!" if ($?);
|
||||
parse_pvols (@pvol);
|
||||
|
||||
# fetch PVOLs (boot)
|
||||
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 ($?);
|
||||
parse_pvols (@pvol);
|
||||
# output: diskYYYY
|
||||
@pvol = `/usr/sbin/ioscan -kFN -C disk 2>/dev/null | cut -f9,13 -d':' | tr -d ':'`;
|
||||
die "ERROR: could not retrieve ioscan info" if ($?);
|
||||
print_header;
|
||||
parse_pvols (@pvol);
|
||||
|
||||
# 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 "ERROR: could not retrieve boot info" if ($?);
|
||||
parse_pvols (@pvol);
|
||||
}
|
||||
|
||||
# footer
|
||||
$footer = qq{
|
||||
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;
|
||||
|
||||
print STDOUT $footer;
|
||||
}
|
||||
|
||||
exit (0);
|
||||
|
||||
@ -191,10 +289,11 @@ pvs.pl - Show physical volume information in a terse way (Linux style).
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
pvs.pl [-h|--help]
|
||||
pvs.pl [-h|--help]
|
||||
[(-g|--vg)=<vg_name>]
|
||||
[(-s|--size)=<MB|GB>]
|
||||
[(-a|--active)]
|
||||
[(-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]
|
Loading…
x
Reference in New Issue
Block a user