From 931f0b763dab5361a00f1260a0882f5da7a8ddc3 Mon Sep 17 00:00:00 2001 From: Keith Ward Date: Fri, 12 Jun 2020 20:43:27 +0100 Subject: [PATCH] Add support for additional properties for Zpool. ashift (Only valid on linux) autoexpand failmode. --- lib/puppet/provider/zpool/zpool.rb | 51 +++++++++++++++++++++++++- lib/puppet/type/zpool.rb | 16 ++++++++ spec/unit/provider/zpool/zpool_spec.rb | 49 +++++++++++++++++++++++++ spec/unit/type/zpool_spec.rb | 2 +- 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/lib/puppet/provider/zpool/zpool.rb b/lib/puppet/provider/zpool/zpool.rb index c095c6a..ce40c0a 100644 --- a/lib/puppet/provider/zpool/zpool.rb +++ b/lib/puppet/provider/zpool/zpool.rb @@ -11,6 +11,13 @@ def self.instances 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) @@ -115,8 +122,18 @@ def build_vdevs 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, @resource[:pool]] + build_vdevs + build_named('spare') + build_named('log'))) + zpool(*([:create] + add_pool_properties + [@resource[:pool]] + build_vdevs + build_named('spare') + build_named('log'))) end def destroy @@ -141,4 +158,36 @@ def exists? 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 + + 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 diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb index 5c479b8..f1618ce 100644 --- a/lib/puppet/type/zpool.rb +++ b/lib/puppet/type/zpool.rb @@ -90,6 +90,22 @@ def insync?(is) desc 'Log disks for this pool. This type does not currently support mirroring of log disks.' end + newproperty(:ashift) do + desc 'The Alignment Shift for the vdevs in the given pool.' + + validate do |_value| + raise Puppet::Error _('This property is only supported on Linux and FreeBSD') unless Facter.value(:kernel) == 'Linux' || Facter.value(:kernel) == 'FreeBSD' + end + end + + newproperty(:autoexpand) do + desc 'The autoexpand setting for the given pool. Valid values are `on` or `off`' + end + + newproperty(:failmode) do + desc 'The failmode setting for the given pool. Valid values are `wait`, `continue` or `panic`' + end + newparam(:pool) do desc 'The name for this pool.' isnamevar diff --git a/spec/unit/provider/zpool/zpool_spec.rb b/spec/unit/provider/zpool/zpool_spec.rb index cfbd2c5..bf17159 100644 --- a/spec/unit/provider/zpool/zpool_spec.rb +++ b/spec/unit/provider/zpool/zpool_spec.rb @@ -158,6 +158,42 @@ end end + describe 'when calling the getters and setters for configurable options' do + [:autoexpand, :failmode].each do |field| + it "should get the #{field} value from the pool" do + allow(provider).to receive(:zpool).with(:get, field, name).and_return("NAME PROPERTY VALUE SOURCE\n#{name} #{field} value local") + expect(provider.send(field)).to eq('value') + end + it "should set #{field}=value" do + expect(provider).to receive(:zpool).with(:set, "#{field}=value", name) + provider.send("#{field}=", 'value') + end + end + end + describe 'when calling the getters and setters for ashift' do + context 'when available' do + it "gets 'ashift' property" do + expect(provider).to receive(:zpool).with(:get, :ashift, name).and_return("NAME PROPERTY VALUE SOURCE\n#{name} ashift value local") + expect(provider.send('ashift')).to eq('value') + end + it 'sets ashift=value' do + expect(provider).to receive(:zpool).with(:set, 'ashift=value', name) + provider.send('ashift=', 'value') + end + end + + context 'when not available' do + it "gets '-' for the ashift property" do + expect(provider).to receive(:zpool).with(:get, :ashift, name).and_raise(RuntimeError, 'not valid') + expect(provider.send('ashift')).to eq('-') + end + it 'does not error out when trying to set ashift' do + expect(provider).to receive(:zpool).with(:set, 'ashift=value', name).and_raise(RuntimeError, 'not valid') + expect { provider.send('ashift=', 'value') }.not_to raise_error + end + end + end + describe 'when calling the getters and setters' do [:disk, :mirror, :raidz, :log, :spare].each do |field| describe "when calling #{field}" do @@ -234,6 +270,19 @@ provider.create end end + + describe 'when creating a zpool with options' do + before(:each) do + resource[:disk] = 'disk1' + end + [:ashift, :autoexpand, :failmode].each do |field| + it "should include field #{field}" do + resource[field] = field + expect(provider).to receive(:zpool).with(:create, '-o', "#{field}=#{field}", name, 'disk1') + provider.create + end + end + end end context '#delete' do diff --git a/spec/unit/type/zpool_spec.rb b/spec/unit/type/zpool_spec.rb index 97eda6f..3ddbc2b 100644 --- a/spec/unit/type/zpool_spec.rb +++ b/spec/unit/type/zpool_spec.rb @@ -2,7 +2,7 @@ describe 'zpool' do describe Puppet::Type.type(:zpool) do - properties = [:ensure, :disk, :mirror, :raidz, :spare, :log] + properties = [:ensure, :disk, :mirror, :raidz, :spare, :log, :autoexpand, :failmode, :ashift] properties.each do |property| it "should have a #{property} property" do expect(described_class.attrclass(property).ancestors).to be_include(Puppet::Property)