diff options
-rw-r--r-- | README.md | 41 | ||||
-rw-r--r-- | functions/round.pp | 9 | ||||
-rw-r--r-- | lib/puppet/functions/fact.rb | 58 | ||||
-rw-r--r-- | lib/puppet/parser/functions/pw_hash.rb | 7 | ||||
-rw-r--r-- | lib/puppet/provider/file_line/ruby.rb | 4 | ||||
-rw-r--r-- | lib/puppet/type/file_line.rb | 8 | ||||
-rw-r--r-- | spec/aliases/integer_spec.rb | 2 | ||||
-rw-r--r-- | spec/functions/pw_hash_spec.rb | 8 | ||||
-rwxr-xr-x | spec/functions/round_spec.rb | 11 | ||||
-rwxr-xr-x | spec/unit/puppet/provider/file_line/ruby_spec.rb | 18 |
10 files changed, 163 insertions, 3 deletions
@@ -115,6 +115,18 @@ file_line { 'bashrc_proxy': In the example above, `match` looks for a line beginning with 'export' followed by 'HTTP_PROXY' and replaces it with the value in line. +Match Example: + + file_line { 'bashrc_proxy': + ensure => present, + path => '/etc/bashrc', + line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128', + match => '^export\ HTTP_PROXY\=', + append_on_no_match => false, + } + +In this code example, `match` looks for a line beginning with export followed by HTTP_PROXY and replaces it with the value in line. If a match is not found, then no changes are made to the file. + Match Example with `ensure => absent`: ```puppet @@ -899,6 +911,31 @@ userlist: ensure_resources('user', hiera_hash('userlist'), {'ensure' => 'present'}) ``` +#### `fact` + +Return the value of a given fact. Supports the use of dot-notation for referring to structured facts. If a fact requested does not exist, returns Undef. + +Example usage: + +```puppet +fact('kernel') +fact('osfamily') +fact('os.architecture') +``` + +Array indexing: + +```puppet +$first_processor = fact('processors.models.0') +$second_processor = fact('processors.models.1') +``` + +Fact containing a "." in the fact name: + +```puppet +fact('vmware."VRA.version"') +``` + #### `flatten` Flattens deeply nested arrays and returns a single flat array as a result. @@ -1513,6 +1550,10 @@ For example, `reject(['aaa','bbb','ccc','aaaddd'], 'aaa')` returns ['bbb','ccc'] Reverses the order of a string or array. +#### `stdlib::round` + + Rounds a number to the nearest integer + *Type*: rvalue. #### `rstrip` diff --git a/functions/round.pp b/functions/round.pp new file mode 100644 index 0000000..6bad92d --- /dev/null +++ b/functions/round.pp @@ -0,0 +1,9 @@ +function stdlib::round( + Numeric $input, +) { + if $input >= 0 { + Integer( $input + 0.5 ) + } else { + Integer( $input - 0.5 ) + } +} diff --git a/lib/puppet/functions/fact.rb b/lib/puppet/functions/fact.rb new file mode 100644 index 0000000..dfb048b --- /dev/null +++ b/lib/puppet/functions/fact.rb @@ -0,0 +1,58 @@ +# Digs into the facts hash using dot-notation +# +# Example usage: +# +# fact('osfamily') +# fact('os.architecture') +# +# Array indexing: +# +# fact('mountpoints."/dev".options.1') +# +# Fact containing a "." in the name: +# +# fact('vmware."VRA.version"') +# +Puppet::Functions.create_function(:fact) do + dispatch :fact do + param 'String', :fact_name + end + + def to_dot_syntax(array_path) + array_path.map do |string| + string.include?('.') ? %Q{"#{string}"} : string + end.join('.') + end + + def fact(fact_name) + facts = closure_scope['facts'] + + # Transform the dot-notation string into an array of paths to walk. Make + # sure to correctly extract double-quoted values containing dots as single + # elements in the path. + path = fact_name.scan(/([^."]+)|(?:")([^"]+)(?:")/).map {|x| x.compact.first } + + walked_path = [] + path.reduce(facts) do |d, k| + return nil if d.nil? || k.nil? + + case + when d.is_a?(Array) + begin + result = d[Integer(k)] + rescue ArgumentError => e + Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is an array; cannot index to '#{k}'") + result = nil + end + when d.is_a?(Hash) + result = d[k] + else + Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is not a collection; cannot walk to '#{k}'") + result = nil + end + + walked_path << k + result + end + end +end diff --git a/lib/puppet/parser/functions/pw_hash.rb b/lib/puppet/parser/functions/pw_hash.rb index d99ee5b..0deeb3a 100644 --- a/lib/puppet/parser/functions/pw_hash.rb +++ b/lib/puppet/parser/functions/pw_hash.rb @@ -27,6 +27,13 @@ Puppet::Parser::Functions::newfunction( environment contains several different operating systems, ensure that they are compatible before using this function.") do |args| raise ArgumentError, "pw_hash(): wrong number of arguments (#{args.size} for 3)" if args.size != 3 + args.map! do |arg| + if arg.is_a? Puppet::Pops::Types::PSensitiveType::Sensitive + arg.unwrap + else + arg + end + end raise ArgumentError, "pw_hash(): first argument must be a string" unless args[0].is_a? String or args[0].nil? raise ArgumentError, "pw_hash(): second argument must be a string" unless args[1].is_a? String hashes = { 'md5' => '1', diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb index 2f6c8ef..16f2709 100644 --- a/lib/puppet/provider/file_line/ruby.rb +++ b/lib/puppet/provider/file_line/ruby.rb @@ -12,7 +12,9 @@ Puppet::Type.type(:file_line).provide(:ruby) do found = lines_count > 0 else match_count = count_matches(new_match_regex) - if resource[:replace].to_s == 'true' + if resource[:append_on_no_match].to_s == 'false' + found = true + elsif resource[:replace].to_s == 'true' found = lines_count > 0 && lines_count == match_count else found = match_count > 0 diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb index 3d691bf..b2357b8 100644 --- a/lib/puppet/type/file_line.rb +++ b/lib/puppet/type/file_line.rb @@ -58,7 +58,7 @@ Puppet::Type.newtype(:file_line) do encoding => "iso-8859-1", } - Files with special characters that are not valid UTF-8 will give the + Files with special characters that are not valid UTF-8 will give the error message "invalid byte sequence in UTF-8". In this case, determine the correct file encoding and specify the correct encoding using the encoding attribute, the value of which needs to be a valid Ruby character @@ -136,6 +136,12 @@ Puppet::Type.newtype(:file_line) do defaultto 'UTF-8' end + newparam(:append_on_no_match) do + desc 'If true, append line if match is not found. If false, do not append line if a match is not found' + newvalues(true, false) + defaultto true + end + # Autorequire the file resource if it's being managed autorequire(:file) do self[:path] diff --git a/spec/aliases/integer_spec.rb b/spec/aliases/integer_spec.rb index aec9fd6..9cf0357 100644 --- a/spec/aliases/integer_spec.rb +++ b/spec/aliases/integer_spec.rb @@ -22,7 +22,7 @@ if Puppet::Util::Package.versioncmp(Puppet.version, '4.5.0') >= 0 [ "foo\nbar", true, 'true', false, 'false', 'iAmAString', '1test', '1 test', 'test 1', 'test 1 test', {}, { 'key' => 'value' }, { 1=> 2 }, '', :undef , 'x', 3.7, '3.7',-3.7, '-342.2315e-12' ].each do |value| describe value.inspect do let(:params) {{ value: value }} - if Gem::Version.new(Puppet.version) >= Gem::Version.new('5.0.0') + if Puppet::Util::Package.versioncmp(Puppet.version, '5.0.0') >= 0 it { is_expected.to compile.and_raise_error(/parameter 'value' expects a Stdlib::Compat::Integer = Variant\[Integer, Pattern\[.*\], Array\[.*\]\] value/) } else it { is_expected.to compile.and_raise_error(/parameter 'value' expects a value of type Integer, Pattern(\[.*\]+)?, or Array/) } diff --git a/spec/functions/pw_hash_spec.rb b/spec/functions/pw_hash_spec.rb index df5348c..9e03464 100644 --- a/spec/functions/pw_hash_spec.rb +++ b/spec/functions/pw_hash_spec.rb @@ -65,5 +65,13 @@ describe 'pw_hash' do it { is_expected.to run.with_params('password', 'sha-256', 'salt').and_return('$5$salt$Gcm6FsVtF/Qa77ZKD.iwsJlCVPY0XSMgLJL0Hnww/c1') } it { is_expected.to run.with_params('password', 'sha-512', 'salt').and_return('$6$salt$IxDD3jeSOb5eB1CX5LBsqZFVkJdido3OUILO5Ifz5iwMuTS4XMS130MTSuDDl3aCI6WouIL9AjRbLCelDCy.g.') } end + + if Puppet::Util::Package.versioncmp(Puppet.version, '4.7.0') >= 0 + describe 'when arguments are sensitive' do + it { is_expected.to run.with_params(Puppet::Pops::Types::PSensitiveType::Sensitive.new('password'), 'md5', 'salt').and_return('$1$salt$qJH7.N4xYta3aEG/dfqo/0') } + it { is_expected.to run.with_params(Puppet::Pops::Types::PSensitiveType::Sensitive.new('password'), 'md5', Puppet::Pops::Types::PSensitiveType::Sensitive.new('salt')).and_return('$1$salt$qJH7.N4xYta3aEG/dfqo/0') } + it { is_expected.to run.with_params('password', 'md5', Puppet::Pops::Types::PSensitiveType::Sensitive.new('salt')).and_return('$1$salt$qJH7.N4xYta3aEG/dfqo/0') } + end + end end end diff --git a/spec/functions/round_spec.rb b/spec/functions/round_spec.rb new file mode 100755 index 0000000..5aa801c --- /dev/null +++ b/spec/functions/round_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe 'stdlib::round' do + it { is_expected.not_to eq(nil) } + it { is_expected.to run.with_params(34.3).and_return(34) } + it { is_expected.to run.with_params(-34.3).and_return(-34) } + it { is_expected.to run.with_params(34.5).and_return(35) } + it { is_expected.to run.with_params(-34.5).and_return(-35) } + it { is_expected.to run.with_params(34.7).and_return(35) } + it { is_expected.to run.with_params(-34.7).and_return(-35) } +end diff --git a/spec/unit/puppet/provider/file_line/ruby_spec.rb b/spec/unit/puppet/provider/file_line/ruby_spec.rb index ab6edf9..dcca4a4 100755 --- a/spec/unit/puppet/provider/file_line/ruby_spec.rb +++ b/spec/unit/puppet/provider/file_line/ruby_spec.rb @@ -194,6 +194,24 @@ describe provider_class, :unless => Puppet::Util::Platform.windows? do @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2") end + + it 'should not add line after no matches found' do + @resource = Puppet::Type::File_line.new( + { + :name => 'foo', + :path => @tmpfile, + :line => 'inserted = line', + :match => '^foo3$', + :append_on_no_match => false, + } + ) + @provider = provider_class.new(@resource) + File.open(@tmpfile, 'w') do |fh| + fh.write("foo1\nfoo = blah\nfoo2\nfoo = baz") + end + expect(@provider.exists?).to be true + expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = blah\nfoo2\nfoo = baz") + end end describe 'using after' do |