diff --git a/lib/puppet/provider/zpool/zpool.rb b/lib/puppet/provider/zpool/zpool.rb index 4c17e73..7d27be3 100644 --- a/lib/puppet/provider/zpool/zpool.rb +++ b/lib/puppet/provider/zpool/zpool.rb @@ -1,195 +1,195 @@ Puppet::Type.type(:zpool).provide(:zpool) do desc 'Provider for zpool.' commands zpool: 'zpool' # NAME SIZE ALLOC FREE CAP HEALTH ALTROOT def self.instances zpool(:list, '-H').split("\n").map do |line| name, _size, _alloc, _free, _cap, _health, _altroot = line.split(%r{\s+}) new(name: name, ensure: :present) end end def get_zpool_property(prop) zpool(:get, prop, @resource[:name]).split("\n").reverse.map { |line| name, _property, value, _source = line.split("\s") value if name == @resource[:name] }.shift end def process_zpool_data(pool_array) if pool_array == [] return Hash.new(:absent) end # get the name and get rid of it pool = {} pool[:pool] = pool_array[0] pool_array.shift tmp = [] # order matters here :( pool_array.reverse_each do |value| sym = nil case value when 'spares' sym = :spare when 'logs' sym = :log when 'cache' sym = :cache when %r{^mirror|^raidz1|^raidz2} sym = (value =~ %r{^mirror}) ? :mirror : :raidz pool[:raid_parity] = 'raidz2' if value =~ %r{^raidz2} else # get full drive name if the value is a partition (Linux only) tmp << if Facter.value(:kernel) == 'Linux' && value =~ %r{/dev/(:?[a-z]+1|disk/by-id/.+-part1)$} execute("lsblk -p -no pkname #{value}").chomp else value end sym = :disk if value == pool_array.first end if sym pool[sym] = (pool[sym]) ? pool[sym].unshift(tmp.reverse.join(' ')) : [tmp.reverse.join(' ')] tmp.clear end end pool end # rubocop:disable Style/AccessorMethodName # rubocop:disable Style/NumericPredicate def get_pool_data # https://docs.oracle.com/cd/E19082-01/817-2271/gbcve/index.html # we could also use zpool iostat -v mypool for a (little bit) cleaner output zpool_opts = case Facter.value(:kernel) # use full device names ("-P") on Linux/ZOL to prevent # mismatches between creation and display paths: when 'Linux' '-P' else '' end out = execute("zpool status #{zpool_opts} #{@resource[:pool]}", failonfail: false, combine: false) zpool_data = out.lines.select { |line| line.index("\t") == 0 }.map { |l| l.strip.split("\s")[0] } zpool_data.shift zpool_data end def current_pool @current_pool = process_zpool_data(get_pool_data) unless defined?(@current_pool) && @current_pool @current_pool end def flush @current_pool = nil end # Adds log and spare def build_named(name) prop = @resource[name.to_sym] if prop [name] + prop.map { |p| p.split(' ') }.flatten else [] end end # query for parity and set the right string def raidzarity (@resource[:raid_parity]) ? @resource[:raid_parity] : 'raidz1' end # handle mirror or raid def handle_multi_arrays(prefix, array) array.map { |a| [prefix] + a.split(' ') }.flatten end # builds up the vdevs for create command def build_vdevs disk = @resource[:disk] mirror = @resource[:mirror] raidz = @resource[:raidz] if disk disk.map { |d| d.split(' ') }.flatten elsif mirror handle_multi_arrays('mirror', mirror) elsif raidz handle_multi_arrays(raidzarity, raidz) end end def add_pool_properties properties = [] [:ashift, :autoexpand, :failmode].each do |property| if (value = @resource[property]) && value != '' properties << '-o' << "#{property}=#{value}" end end properties end def create zpool(*([:create] + add_pool_properties + [@resource[:pool]] + build_vdevs + build_named('spare') + build_named('log') + build_named('cache'))) end def destroy zpool :destroy, @resource[:pool] end def exists? if current_pool[:pool] == :absent false else true end end [:disk, :mirror, :raidz, :log, :spare, :cache].each do |field| define_method(field) do current_pool[field] end # rubocop:disable Style/SignalException define_method(field.to_s + '=') do |should| fail "zpool #{field} can't be changed. should be #{should}, currently is #{current_pool[field]}" end end [:autoexpand, :failmode].each do |field| define_method(field) do get_zpool_property(field) end define_method(field.to_s + '=') do |should| zpool(:set, "#{field}=#{should}", @resource[:name]) end end # Borrow the code from the ZFS provider here so that we catch and return '-' # as ashift is linux only. # see lib/puppet/provider/zfs/zfs.rb - PARAMETER_UNSET_OR_NOT_AVAILABLE = '-'.freeze + PARAMETER_UNSET_OR_NOT_AVAILABLE = '-'.freeze unless defined? PARAMETER_UNSET_OR_NOT_AVAILABLE define_method(:ashift) do begin get_zpool_property(:ashift) rescue PARAMETER_UNSET_OR_NOT_AVAILABLE end end define_method('ashift=') do |should| begin zpool(:set, "ashift=#{should}", @resource[:name]) rescue PARAMETER_UNSET_OR_NOT_AVAILABLE end end end