# # (c) Jan Gehring # # vim: set ts=3 sw=3 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. =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; 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 and 0-9."); } 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;