diff --git a/lib/puppet/provider/logical_volume/lvm.rb b/lib/puppet/provider/logical_volume/lvm.rb index 61a6f047..2d15ee66 100644 --- a/lib/puppet/provider/logical_volume/lvm.rb +++ b/lib/puppet/provider/logical_volume/lvm.rb @@ -13,7 +13,9 @@ :blkid => 'blkid', :dmsetup => 'dmsetup', :lvconvert => 'lvconvert', - :lvdisplay => 'lvdisplay' + :lvdisplay => 'lvdisplay', + :vgs => 'vgs', + :pvs => 'pvs' optional_commands :xfs_growfs => 'xfs_growfs', :resize4fs => 'resize4fs' @@ -137,6 +139,85 @@ def exists? lvs(@resource[:volume_group]) =~ lvs_pattern end + def extents + lvm_size_units = { "K" => 1, "M" => 1024, "G" => 1024**2, "T" => 1024**3, "P" => 1024**4, "E" => 1024**5 } + + if @resource[:extents] =~ /^(\d+)((%)?(vg))?$/i + extents_size = $1.to_f + extents_full_type = $2.downcase unless $2.nil? + end + + raw_vgs = vgs('--noheading', '-o','name,vg_extent_count,seg_size,vg_extent_size', path) + + # Calculate the total extents of the Volume Group and the total used extents of the Logical Volume. + vgs_size = Hash.new + total_vgs_extents = 0 + raw_vgs.split("\n").each do |lvs| + + if lvs =~ /\s+(\w+)\s+(\d+)\s+(\d+(\.\d+)?)([KMGTPE])\s+(\d+(\.\d+)?)([KMGTPE])/i + vg_name = $1 + vg_extents_count = $2.to_i + + lv_size = $3.to_f + lv_unit = $5.upcase + + ex_size = $6.to_f + ex_unit = $8.upcase + + # Number of extents in use by LV + lv_extents_count = (lv_size / ex_size) * (lvm_size_units[lv_unit] / lvm_size_units[ex_unit]) + + end + total_vgs_extents += vg_extents_count unless vgs_size.keys.include?(vg_name) + vgs_size[vg_name] ||= 0 + vgs_size[vg_name] += lv_extents_count + end + + total_used_lvs_extents = vgs_size.values.inject(:+) + # End calculation + + if !extents_full_type.nil? and extents_full_type.eql? '%vg' + current_perc = ((total_used_lvs_extents / total_vgs_extents) * 100).round(0).to_s + current_value = current_perc + extents_full_type + + return current_value + end + + return total_used_lvs_extents.to_s + end + + def extents=(new_extents) + + current_extents = extents() + + if current_extents =~ /^(\d+(\.\d+)?)(%vg)?$/i + current_extents_value = $1.to_f + current_extents_type = $3.upcase unless $3.nil? + end + + if new_extents =~ /^(\d+(%vg)?)?$/i + new_extents_value = $1.to_i + new_extents_type = $2.upcase unless $2.nil? + + new_extent_size = new_extents_value.to_s + new_extent_size += new_extents_type unless new_extents_type.nil? + end + + # If types does not match, do not resize + unless current_extents_type.eql? new_extents_type + fail("Cannot resize with different types (current: #{current_extents_type} vs new: #{new_extents_type}") + end + + # Reduce in size is not possible + if new_extents_value.to_f < current_extents_value + fail("Decreasing the size requires manual intervention (#{new_extents_value} < #{current_extents_value})") + end + + lvextend('--extents', new_extent_size, path) + + resizefs(path, new_extent_size) + end + def size if @resource[:size] =~ /^\d+\.?\d{0,2}([KMGTPE])/i unit = $1.downcase @@ -201,18 +282,7 @@ def size=(new_size) lvextend( '-L', new_size, path) || fail( "Cannot extend to size #{new_size} because lvextend failed." ) - unless @resource[:resize_fs] == :false or @resource[:resize_fs] == false or @resource[:resize_fs] == 'false' - blkid_type = blkid(path) - if command(:resize4fs) and blkid_type =~ /\bTYPE=\"(ext4)\"/ - resize4fs( path) || fail( "Cannot resize file system to size #{new_size} because resize2fs failed." ) - elsif blkid_type =~ /\bTYPE=\"(ext[34])\"/ - resize2fs( path) || fail( "Cannot resize file system to size #{new_size} because resize2fs failed." ) - elsif blkid_type =~ /\bTYPE=\"(xfs)\"/ - xfs_growfs( path) || fail( "Cannot resize filesystem to size #{new_size} because xfs_growfs failed." ) - elsif blkid_type =~ /\bTYPE=\"(swap)\"/ - swapoff( path) && mkswap( path) && swapon( path) || fail( "Cannot resize swap to size #{new_size} because mkswap failed." ) - end - end + resizefs(path, new_size) end end @@ -305,4 +375,19 @@ def vgpath "/dev/#{@resource[:volume_group]}" end + def resizefs(path, new_size) + unless @resource[:resize_fs] == :false or @resource[:resize_fs] == false or @resource[:resize_fs] == 'false' + blkid_type = blkid(path) + if command(:resize4fs) and blkid_type =~ /\bTYPE=\"(ext4)\"/ + resize4fs( path) || fail( "Cannot resize file system to size #{new_size} because resize2fs failed." ) + elsif blkid_type =~ /\bTYPE=\"(ext[34])\"/ + resize2fs( path) || fail( "Cannot resize file system to size #{new_size} because resize2fs failed." ) + elsif blkid_type =~ /\bTYPE=\"(xfs)\"/ + xfs_growfs( path) || fail( "Cannot resize filesystem to size #{new_size} because xfs_growfs failed." ) + elsif blkid_type =~ /\bTYPE=\"(swap)\"/ + swapoff( path) && mkswap( path) && swapon( path) || fail( "Cannot resize swap to size #{new_size} because mkswap failed." ) + end + end + end + end diff --git a/lib/puppet/type/logical_volume.rb b/lib/puppet/type/logical_volume.rb index 4a736f1d..8bbc3257 100644 --- a/lib/puppet/type/logical_volume.rb +++ b/lib/puppet/type/logical_volume.rb @@ -58,13 +58,47 @@ def insync?(is) end end - newparam(:extents) do - desc "The number of logical extents to allocate for the new logical volume. Set to undef to use all available space" + newparam(:resize_extents) do + desc "Do resize when setting extents" + validate do |value| + unless [:true, true, "true", :false, false, "false"].include?(value) + raise ArgumentError , "resize_extents must be either be true or false" + end + end + defaultto false + end + + newproperty(:extents) do + desc "The number of logical extents to allocate for the logical volume." validate do |value| unless value =~ /^\d+(%(?:vg|pvs|free|origin)?)?$/i raise ArgumentError , "#{value} is not a valid logical volume extent" end end + def insync?(is) + unless [:true, true, "true"].include?(@resource[:resize_extents]) + return true + end + + if is =~ /^(\d+(\.\d+)?)(%)?(vg)?$/i + current_value = $1.to_f + current_percent = !$3.nil? + current_type = $4.downcase unless $4.nil? + end + + if should =~ /^(\d+)(%)?(vg|pvs|free|origin)?$/i + new_value = $1.to_f + new_percent = !$2.nil? + new_type = $3.downcase unless $3.nil? + if not new_type.nil? and ['origin', 'pvs', 'free'].include?(new_type) + warn("Warning: #{new_type} is not supported as extents resize, currently set to #{should} and resize_extents set to #{@resource[:resize_extents]}") + return true + end + end + + new_value <= current_value + + end end newparam(:persistent) do diff --git a/manifests/logical_volume.pp b/manifests/logical_volume.pp index d38ce4ec..f4488014 100644 --- a/manifests/logical_volume.pp +++ b/manifests/logical_volume.pp @@ -28,6 +28,7 @@ $no_sync = undef, $region_size = undef, $alloc = undef, + $resize_extents = undef, ) { validate_bool($mountpath_require) @@ -95,7 +96,8 @@ mirrorlog => $mirrorlog, no_sync => $no_sync, region_size => $region_size, - alloc => $alloc + alloc => $alloc, + resize_extents => $resize_extents, } if $createfs {