# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Commands::LVM - Get LVM Information =head1 DESCRIPTION With this module you can get information of your lvm setup. Version <= 1.0: All these functions will not be reported. All these functions are not idempotent. =head1 SYNOPSIS use Rex::Commands::LVM; my @physical_devices = pvs; my @volume_groups = vgs; my @logical_volumes = lvs; =head1 EXPORTED FUNCTIONS =over 4 =cut package Rex::Commands::LVM; { $Rex::Commands::LVM::VERSION = '0.55.3'; } use strict; use warnings; require Rex::Exporter; use base qw(Rex::Exporter); use vars qw(@EXPORT); @EXPORT = qw(pvs vgs lvs pvcreate vgcreate lvcreate vgextend); use Rex::Commands::Run; =item pvs Get Information of all your physical volumes. use Data::Dumper; use Rex::Commands::LVM; task "lvm", sub { my @physical_volumes = pvs; for my $physical_volume (@physical_volumes) { say Dumper($physical_volume); } }; =cut sub pvs { my @lines = run 'pvdisplay --units b --columns --separator "|" --noheadings'; if ( $? != 0 ) { die("Error running pvdisplay"); } my @ret; for my $line (@lines) { chomp $line; $line =~ s/^\s+//g; my ( $phy_vol, $vol_group, $format, $attr, $psize, $pfree ) = split( /\|/, $line ); $pfree =~ s/B$//; $psize =~ s/B$//; push( @ret, { physical_volume => $phy_vol, volume_group => $vol_group, format => $format, attributes => $attr, size => $psize, free => $pfree, } ); } return @ret; } =item vgs Get Information of all your volume groups. use Data::Dumper; use Rex::Commands::LVM; task "lvm", sub { my @volume_groups = vgs; for my $volume_group (@volume_groups) { say Dumper($volume_group); } }; =cut sub vgs { my ($vg) = @_; my $cmd = 'vgdisplay --units b --columns --separator "|" --noheadings -o "pv_name,vg_name,vg_size,vg_free,vg_attr"'; if ($vg) { $cmd .= " $vg"; } my @lines = run $cmd; if ( $? != 0 ) { die("Error running vgdisplay"); } my @ret; for my $line (@lines) { chomp $line; $line =~ s/^\s+//g; my ( $pv_name, $vg_name, $vg_size, $vg_free, $vg_attr ) = split( /\|/, $line ); $vg_free =~ s/B$//; $vg_size =~ s/B$//; push( @ret, { physical_volume => $pv_name, volume_group => $vg_name, size => $vg_size, free => $vg_free, attributes => $vg_attr, } ); } return @ret; } =item lvs Get Information of all your logical volumes. use Data::Dumper; use Rex::Commands::LVM; task "lvm", sub { my @logical_volumes = lvs; for my $logical_volume (@logical_volumes) { say Dumper($logical_volume); } }; =cut sub lvs { my ($vg) = @_; my $cmd = 'lvdisplay --units b --columns --separator "|" -o "lv_name,vg_name,lv_attr,lv_size" --noheading'; if ($vg) { $cmd .= " " . $vg; } my @lines = run $cmd; if ( $? != 0 ) { die("Error running lvdisplay"); } my @ret; for my $line (@lines) { chomp $line; $line =~ s/^\s+//g; my ( $lv_name, $vg_name, $lv_attr, $lv_size ) = split( /\|/, $line ); $lv_size =~ s/B$//; push( @ret, { name => $lv_name, path => "/dev/$vg_name/$lv_name", attributes => $lv_attr, size => $lv_size, } ); } return @ret; } sub pvcreate { my ($dev) = @_; my $s = run "pvcreate $dev"; if ( $? != 0 ) { die("Error creating pv.\n$s\n"); } return 1; } sub vgcreate { my ( $vgname, @devices ) = @_; my $s = run "vgcreate $vgname " . join( " ", @devices ); if ( $? != 0 ) { die("Error creating vg.\n$s\n"); } return 1; } sub lvcreate { my ( $lvname, %option ) = @_; if ( !exists $option{size} || !exists $option{onvg} ) { die("Missing parameter size or onvg."); } unless ( $lvname =~ m/^[a-z0-9\-\._]+$/i ) { die("Error in lvname. Allowed characters a-z, 0-9 and _-. ."); } my $size = $option{size}; if ( $size =~ m/^[0-9]+$/ ) { $size .= "M"; } my $onvg = $option{onvg}; my $s = run "lvcreate -n $lvname -L $size $onvg"; my $lv_path = $option{onvg} . "/" . $lvname; if ( exists $option{fstype} ) { if ( can_run("mkfs.$option{fstype}") ) { Rex::Logger::info("Creating filesystem $option{fstype} on /dev/$lv_path"); run "mkfs.$option{fstype} /dev/$lv_path"; } elsif ( $option{fstype} eq "swap" ) { Rex::Logger::info("Creating swap space on /dev/$lv_path"); run "mkswap -f /dev/$lv_path"; } else { die("Can't format partition with $option{fstype}"); } } if ( $? != 0 ) { die("Error creating lv.\n$s\n"); } return $lv_path; } sub vgextend { my ( $vgname, @devices ) = @_; my $s = run "vgextend $vgname " . join( " ", @devices ); if ( $? != 0 ) { die("Error extending vg.\n$s\n"); } return 1; } =back =cut 1;