diff options
35 files changed, 1175 insertions, 56 deletions
@@ -1,3 +1,25 @@ +2013-05-06 - Jeff McCune <jeff@puppetlabs.com> - 4.1.0 + * (#20582) Restore facter_dot_d to stdlib for PE users (3b887c8) + * (maint) Update Gemfile with GEM_FACTER_VERSION (f44d535) + +2013-05-06 - Alex Cline <acline@us.ibm.com> - 4.1.0 + * Terser method of string to array conversion courtesy of ethooz. (d38bce0) + +2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0 + * Refactor ensure_resource expectations (b33cc24) + +2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0 + * Changed str-to-array conversion and removed abbreviation. (de253db) + +2013-05-03 - Alex Cline <acline@us.ibm.com> 4.1.0 + * (#20548) Allow an array of resource titles to be passed into the ensure_resource function (e08734a) + +2013-05-02 - Raphaƫl Pinson <raphael.pinson@camptocamp.com> - 4.1.0 + * Add a dirname function (2ba9e47) + +2013-04-29 - Mark Smith-Guerrero <msmithgu@gmail.com> - 4.1.0 + * (maint) Fix a small typo in hash() description (928036a) + 2013-04-12 - Jeff McCune <jeff@puppetlabs.com> - 4.0.2 * Update user information in gemspec to make the intent of the Gem clear. @@ -24,7 +24,16 @@ group :development, :test do gem 'rspec-puppet', :require => false end -if puppetversion = ENV['PUPPET_GEM_VERSION'] +facterversion = ENV['GEM_FACTER_VERSION'] +if facterversion + gem 'facter', *location_for(facterversion) +else + gem 'facter', :require => false +end + +ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION'] +puppetversion = ENV['GEM_PUPPET_VERSION'] +if puppetversion gem 'puppet', *location_for(puppetversion) else gem 'puppet', :require => false @@ -1,5 +1,5 @@ name 'puppetlabs-stdlib' -version '4.0.2' +version '4.1.0' source 'git://github.com/puppetlabs/puppetlabs-stdlib.git' author 'puppetlabs' license 'Apache 2.0' diff --git a/README.markdown b/README.markdown index 0efaf16..1e51e1d 100644 --- a/README.markdown +++ b/README.markdown @@ -83,6 +83,15 @@ converted to arrays of alternating keys and values. - *Type*: rvalue +base64 +-------- +Converts a string to and from base64 encoding. +Requires an action ['encode','decode'] and either a plain or base64 encoded +string + + +- *Type*: rvalue + bool2num -------- Converts a boolean to a number. Converts the values: @@ -195,6 +204,55 @@ Would return: ['a','c'] - *Type*: rvalue +delete_values +------------- +Deletes all instances of a given value from a hash. + +*Examples:* + + delete_values({'a'=>'A','b'=>'B','c'=>'C','B'=>'D'}, 'B') + +Would return: {'a'=>'A','c'=>'C','B'=>'D'} + + +delete_undef_values +------------------- +Deletes all instances of the undef value from an array or hash. + +*Examples:* + + $hash = delete_undef_values({a=>'A', b=>'', c=>undef, d => false}) + +Would return: {a => 'A', b => '', d => false} + + $array = delete_undef_values(['A','',undef,false]) + +Would return: ['A','',false] + +- *Type*: rvalue + +difference +---------- +This function returns the difference between two arrays. +The returned array is a copy of the original array, removing any items that +also appear in the second array. + +*Examples:* + + difference(["a","b","c"],["b","c","d"]) + +Would return: ["a"] + +dirname +------- +Returns the `dirname` of a path. + +*Examples:* + + dirname('/path/to/a/file.ext') + +Would return: '/path/to/a' + downcase -------- Converts the case of a string or all strings in an array to lower case. @@ -227,12 +285,17 @@ resource. This example only creates the resource if it does not already exist: - ensure_resource('user, 'dan', {'ensure' => 'present' }) + ensure_resource('user', 'dan', {'ensure' => 'present' }) If the resource already exists but does not match the specified parameters, this function will attempt to recreate the resource leading to a duplicate resource definition error. +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + - *Type*: statement @@ -390,7 +453,7 @@ Example: hash ---- -This function converts and array into a hash. +This function converts an array into a hash. *Examples:* @@ -401,6 +464,16 @@ Would return: {'a'=>1,'b'=>2,'c'=>3} - *Type*: rvalue +intersection +----------- +This function returns an array an intersection of two. + +*Examples:* + + intersection(["a","b","c"],["b","c","d"]) + +Would return: ["b","c"] + is_array -------- Returns true if the variable passed to this function is an array. @@ -853,6 +926,17 @@ Returns the type when passed a variable. Type can be one of: - *Type*: rvalue +union +----- +This function returns a union of two arrays. + +*Examples:* + + union(["a","b","c"],["b","c","d"]) + +Would return: ["a","b","c","d"] + + unique ------ This function will remove duplicates from strings and arrays. @@ -886,7 +970,7 @@ Converts a string or an array of strings to uppercase. Will return: - ASDF + ABCD - *Type*: rvalue diff --git a/lib/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb new file mode 100644 index 0000000..e414b20 --- /dev/null +++ b/lib/facter/facter_dot_d.rb @@ -0,0 +1,202 @@ +# A Facter plugin that loads facts from /etc/facter/facts.d +# and /etc/puppetlabs/facter/facts.d. +# +# Facts can be in the form of JSON, YAML or Text files +# and any executable that returns key=value pairs. +# +# In the case of scripts you can also create a file that +# contains a cache TTL. For foo.sh store the ttl as just +# a number in foo.sh.ttl +# +# The cache is stored in /tmp/facts_cache.yaml as a mode +# 600 file and will have the end result of not calling your +# fact scripts more often than is needed + +class Facter::Util::DotD + require 'yaml' + + def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") + @dir = dir + @cache_file = cache_file + @cache = nil + @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} + end + + def entries + Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } + rescue + [] + end + + def fact_type(file) + extension = File.extname(file) + + type = @types[extension] || :unknown + + type = :script if type == :unknown && File.executable?(file) + + return type + end + + def txt_parser(file) + File.readlines(file).each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 + + Facter.add(var) do + setcode { val } + end + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end + + def json_parser(file) + begin + require 'json' + rescue LoadError + retry if require 'rubygems' + raise + end + + JSON.load(File.read(file)).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + end + + def yaml_parser(file) + require 'yaml' + + YAML.load_file(file).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + end + + def script_parser(file) + result = cache_lookup(file) + ttl = cache_time(file) + + unless result + result = Facter::Util::Resolution.exec(file) + + if ttl > 0 + Facter.debug("Updating cache for #{file}") + cache_store(file, result) + cache_save! + end + else + Facter.debug("Using cached data for #{file}") + end + + result.split("\n").each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 + + Facter.add(var) do + setcode { val } + end + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") + Facter.debug(e.backtrace.join("\n\t")) + end + + def cache_save! + cache = load_cache + File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } + rescue + end + + def cache_store(file, data) + load_cache + + @cache[file] = {:data => data, :stored => Time.now.to_i} + rescue + end + + def cache_lookup(file) + cache = load_cache + + return nil if cache.empty? + + ttl = cache_time(file) + + if cache[file] + now = Time.now.to_i + + return cache[file][:data] if ttl == -1 + return cache[file][:data] if (now - cache[file][:stored]) <= ttl + return nil + else + return nil + end + rescue + return nil + end + + def cache_time(file) + meta = file + ".ttl" + + return File.read(meta).chomp.to_i + rescue + return 0 + end + + def load_cache + unless @cache + if File.exist?(@cache_file) + @cache = YAML.load_file(@cache_file) + else + @cache = {} + end + end + + return @cache + rescue + @cache = {} + return @cache + end + + def create + entries.each do |fact| + type = fact_type(fact) + parser = "#{type}_parser" + + if respond_to?("#{type}_parser") + Facter.debug("Parsing #{fact} using #{parser}") + + send(parser, fact) + end + end + end +end + + +mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/) +if mdata + (major, minor, patch) = mdata.captures.map { |v| v.to_i } + if major < 2 + # Facter 1.7 introduced external facts support directly + unless major == 1 and minor > 6 + Facter::Util::DotD.new("/etc/facter/facts.d").create + Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create + + # Windows has a different configuration directory that defaults to a vendor + # specific sub directory of the %COMMON_APPDATA% directory. + if Dir.const_defined? 'COMMON_APPDATA' then + windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d') + Facter::Util::DotD.new(windows_facts_dot_d).create + end + end + end +end diff --git a/lib/puppet/parser/functions/base64.rb b/lib/puppet/parser/functions/base64.rb new file mode 100644 index 0000000..d9a590a --- /dev/null +++ b/lib/puppet/parser/functions/base64.rb @@ -0,0 +1,37 @@ +module Puppet::Parser::Functions + + newfunction(:base64, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args| + + Base64 encode or decode a string based on the command and the string submitted + + Usage: + + $encodestring = base64('encode','thestring') + $decodestring = base64('decode','dGhlc3RyaW5n') + + ENDHEREDOC + + require 'base64' + + raise Puppet::ParseError, ("base64(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2 + + actions = ['encode','decode'] + + unless actions.include?(args[0]) + raise Puppet::ParseError, ("base64(): the first argument must be one of 'encode' or 'decode'") + end + + unless args[1].is_a?(String) + raise Puppet::ParseError, ("base64(): the second argument must be a string to base64") + end + + case args[0] + when 'encode' + result = Base64.encode64(args[1]) + when 'decode' + result = Base64.decode64(args[1]) + end + + return result + end +end diff --git a/lib/puppet/parser/functions/delete_undef_values.rb b/lib/puppet/parser/functions/delete_undef_values.rb new file mode 100644 index 0000000..4eecab2 --- /dev/null +++ b/lib/puppet/parser/functions/delete_undef_values.rb @@ -0,0 +1,34 @@ +module Puppet::Parser::Functions + newfunction(:delete_undef_values, :type => :rvalue, :doc => <<-EOS +Returns a copy of input hash or array with all undefs deleted. + +*Examples:* + + $hash = delete_undef_values({a=>'A', b=>'', c=>undef, d => false}) + +Would return: {a => 'A', b => '', d => false} + + $array = delete_undef_values(['A','',undef,false]) + +Would return: ['A','',false] + + EOS + ) do |args| + + raise(Puppet::ParseError, + "delete_undef_values(): Wrong number of arguments given " + + "(#{args.size})") if args.size < 1 + + result = args[0] + if result.is_a?(Hash) + result.delete_if {|key, val| val.equal? :undef} + elsif result.is_a?(Array) + result.delete :undef + else + raise(Puppet::ParseError, + "delete_undef_values(): Wrong argument type #{args[0].class} " + + "for first argument") + end + result + end +end diff --git a/lib/puppet/parser/functions/delete_values.rb b/lib/puppet/parser/functions/delete_values.rb new file mode 100644 index 0000000..2fcbd16 --- /dev/null +++ b/lib/puppet/parser/functions/delete_values.rb @@ -0,0 +1,27 @@ +module Puppet::Parser::Functions + newfunction(:delete_values, :type => :rvalue, :doc => <<-EOS +Deletes all instances of a given value from a hash. + +*Examples:* + + delete_values({'a'=>'A','b'=>'B','c'=>'C','B'=>'D'}, 'B') + +Would return: {'a'=>'A','c'=>'C','B'=>'D'} + + EOS + ) do |arguments| + + raise(Puppet::ParseError, + "delete_values(): Wrong number of arguments given " + + "(#{arguments.size} of 2)") if arguments.size != 2 + + hash = arguments[0] + item = arguments[1] + + if not hash.is_a?(Hash) + raise(TypeError, "delete_values(): First argument must be a Hash. " + \ + "Given an" " argument of class #{hash.class}.") + end + hash.delete_if { |key, val| item == val } + end +end diff --git a/lib/puppet/parser/functions/difference.rb b/lib/puppet/parser/functions/difference.rb new file mode 100644 index 0000000..cd258f7 --- /dev/null +++ b/lib/puppet/parser/functions/difference.rb @@ -0,0 +1,36 @@ +# +# difference.rb +# + +module Puppet::Parser::Functions + newfunction(:difference, :type => :rvalue, :doc => <<-EOS +This function returns the difference between two arrays. +The returned array is a copy of the original array, removing any items that +also appear in the second array. + +*Examples:* + + difference(["a","b","c"],["b","c","d"]) + +Would return: ["a"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "difference(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'difference(): Requires 2 arrays') + end + + result = first - second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/dirname.rb b/lib/puppet/parser/functions/dirname.rb new file mode 100644 index 0000000..ea8cc1e --- /dev/null +++ b/lib/puppet/parser/functions/dirname.rb @@ -0,0 +1,15 @@ +module Puppet::Parser::Functions + newfunction(:dirname, :type => :rvalue, :doc => <<-EOS + Returns the dirname of a path. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "dirname(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + path = arguments[0] + return File.dirname(path) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/ensure_resource.rb b/lib/puppet/parser/functions/ensure_resource.rb index fba2035..05e5593 100644 --- a/lib/puppet/parser/functions/ensure_resource.rb +++ b/lib/puppet/parser/functions/ensure_resource.rb @@ -13,23 +13,33 @@ resource. This example only creates the resource if it does not already exist: - ensure_resource('user, 'dan', {'ensure' => 'present' }) + ensure_resource('user', 'dan', {'ensure' => 'present' }) If the resource already exists but does not match the specified parameters, this function will attempt to recreate the resource leading to a duplicate resource definition error. +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + ENDOFDOC ) do |vals| type, title, params = vals raise(ArgumentError, 'Must specify a type') unless type raise(ArgumentError, 'Must specify a title') unless title params ||= {} - Puppet::Parser::Functions.function(:defined_with_params) - if function_defined_with_params(["#{type}[#{title}]", params]) - Puppet.debug("Resource #{type}[#{title}] not created b/c it already exists") - else - Puppet::Parser::Functions.function(:create_resources) - function_create_resources([type.capitalize, { title => params }]) + + items = [title].flatten + + items.each do |item| + Puppet::Parser::Functions.function(:defined_with_params) + if function_defined_with_params(["#{type}[#{item}]", params]) + Puppet.debug("Resource #{type}[#{item}] not created because it already exists") + else + Puppet::Parser::Functions.function(:create_resources) + function_create_resources([type.capitalize, { item => params }]) + end end end diff --git a/lib/puppet/parser/functions/hash.rb b/lib/puppet/parser/functions/hash.rb index 453ba1e..8cc4823 100644 --- a/lib/puppet/parser/functions/hash.rb +++ b/lib/puppet/parser/functions/hash.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:hash, :type => :rvalue, :doc => <<-EOS -This function converts and array into a hash. +This function converts an array into a hash. *Examples:* diff --git a/lib/puppet/parser/functions/intersection.rb b/lib/puppet/parser/functions/intersection.rb new file mode 100644 index 0000000..48f02e9 --- /dev/null +++ b/lib/puppet/parser/functions/intersection.rb @@ -0,0 +1,34 @@ +# +# intersection.rb +# + +module Puppet::Parser::Functions + newfunction(:intersection, :type => :rvalue, :doc => <<-EOS +This function returns an array an intersection of two. + +*Examples:* + + intersection(["a","b","c"],["b","c","d"]) + +Would return: ["b","c"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "intersection(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'intersection(): Requires 2 arrays') + end + + result = first & second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/range.rb b/lib/puppet/parser/functions/range.rb index 825617b..0849491 100644 --- a/lib/puppet/parser/functions/range.rb +++ b/lib/puppet/parser/functions/range.rb @@ -27,6 +27,13 @@ Will return: ["a","b","c"] range("host01", "host10") Will return: ["host01", "host02", ..., "host09", "host10"] + +Passing a third argument will cause the generated range to step by that +interval, e.g. + + range("0", "9", "2") + +Will return: [0,2,4,6,8] EOS ) do |arguments| @@ -37,6 +44,7 @@ Will return: ["host01", "host02", ..., "host09", "host10"] if arguments.size > 1 start = arguments[0] stop = arguments[1] + step = arguments[2].nil? ? 1 : arguments[2].to_i.abs type = '..' # We select simplest type for Range available in Ruby ... @@ -71,7 +79,7 @@ Will return: ["host01", "host02", ..., "host09", "host10"] when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ... end - result = range.collect { |i| i } # Get them all ... Pokemon ... + result = range.step(step).collect { |i| i } # Get them all ... Pokemon ... return result end diff --git a/lib/puppet/parser/functions/union.rb b/lib/puppet/parser/functions/union.rb new file mode 100644 index 0000000..c91bb80 --- /dev/null +++ b/lib/puppet/parser/functions/union.rb @@ -0,0 +1,34 @@ +# +# union.rb +# + +module Puppet::Parser::Functions + newfunction(:union, :type => :rvalue, :doc => <<-EOS +This function returns a union of two arrays. + +*Examples:* + + union(["a","b","c"],["b","c","d"]) + +Would return: ["a","b","c","d"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "union(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'union(): Requires 2 arrays') + end + + result = first | second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/uriescape.rb b/lib/puppet/parser/functions/uriescape.rb index 67b93a6..0d81de5 100644 --- a/lib/puppet/parser/functions/uriescape.rb +++ b/lib/puppet/parser/functions/uriescape.rb @@ -15,7 +15,6 @@ module Puppet::Parser::Functions value = arguments[0] klass = value.class - unsafe = ":/?#[]@!$&'()*+,;= " unless [Array, String].include?(klass) raise(Puppet::ParseError, 'uriescape(): Requires either ' + @@ -26,7 +25,7 @@ module Puppet::Parser::Functions # Numbers in Puppet are often string-encoded which is troublesome ... result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i } else - result = URI.escape(value,unsafe) + result = URI.escape(value) end return result diff --git a/lib/puppet/parser/functions/validate_ipv4_address.rb b/lib/puppet/parser/functions/validate_ipv4_address.rb new file mode 100644 index 0000000..fc02748 --- /dev/null +++ b/lib/puppet/parser/functions/validate_ipv4_address.rb @@ -0,0 +1,48 @@ +module Puppet::Parser::Functions + + newfunction(:validate_ipv4_address, :doc => <<-ENDHEREDOC + Validate that all values passed are valid IPv4 addresses. + Fail compilation if any value fails this check. + + The following values will pass: + + $my_ip = "1.2.3.4" + validate_ipv4_address($my_ip) + validate_bool("8.8.8.8", "172.16.0.1", $my_ip) + + The following values will fail, causing compilation to abort: + + $some_array = [ 1, true, false, "garbage string", "3ffe:505:2" ] + validate_ipv4_address($some_array) + + ENDHEREDOC + ) do |args| + + require "ipaddr" + rescuable_exceptions = [ ArgumentError ] + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + unless args.length > 0 then + raise Puppet::ParseError, ("validate_ipv4_address(): wrong number of arguments (#{args.length}; must be > 0)") + end + + args.each do |arg| + unless arg.is_a?(String) + raise Puppet::ParseError, "#{arg.inspect} is not a string." + end + + begin + unless IPAddr.new(arg).ipv4? + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address." + end + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address." + end + end + + end + +end diff --git a/lib/puppet/parser/functions/validate_ipv6_address.rb b/lib/puppet/parser/functions/validate_ipv6_address.rb new file mode 100644 index 0000000..b0f2558 --- /dev/null +++ b/lib/puppet/parser/functions/validate_ipv6_address.rb @@ -0,0 +1,49 @@ +module Puppet::Parser::Functions + + newfunction(:validate_ipv6_address, :doc => <<-ENDHEREDOC + Validate that all values passed are valid IPv6 addresses. + Fail compilation if any value fails this check. + + The following values will pass: + + $my_ip = "3ffe:505:2" + validate_ipv6_address(1) + validate_ipv6_address($my_ip) + validate_bool("fe80::baf6:b1ff:fe19:7507", $my_ip) + + The following values will fail, causing compilation to abort: + + $some_array = [ true, false, "garbage string", "1.2.3.4" ] + validate_ipv6_address($some_array) + + ENDHEREDOC + ) do |args| + + require "ipaddr" + rescuable_exceptions = [ ArgumentError ] + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + unless args.length > 0 then + raise Puppet::ParseError, ("validate_ipv6_address(): wrong number of arguments (#{args.length}; must be > 0)") + end + + args.each do |arg| + unless arg.is_a?(String) + raise Puppet::ParseError, "#{arg.inspect} is not a string." + end + + begin + unless IPAddr.new(arg).ipv6? + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address." + end + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address." + end + end + + end + +end diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb index a3219d3..3cb9f6e 100644 --- a/lib/puppet/provider/file_line/ruby.rb +++ b/lib/puppet/provider/file_line/ruby.rb @@ -1,4 +1,3 @@ - Puppet::Type.type(:file_line).provide(:ruby) do def exists? @@ -35,8 +34,8 @@ Puppet::Type.type(:file_line).provide(:ruby) do def handle_create_with_match() regex = resource[:match] ? Regexp.new(resource[:match]) : nil match_count = lines.select { |l| regex.match(l) }.size - if match_count > 1 - raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" + if match_count > 1 && resource[:multiple].to_s != 'true' + raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" end File.open(resource[:path], 'w') do |fh| lines.each do |l| diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb index f71a4bc..14946bb 100644 --- a/lib/puppet/type/file_line.rb +++ b/lib/puppet/type/file_line.rb @@ -37,6 +37,11 @@ Puppet::Type.newtype(:file_line) do 'if a match is found, we replace that line rather than adding a new line.' end + newparam(:multiple) do + desc 'An optional value to determine if match can change multiple lines.' + newvalues(true, false) + end + newparam(:line) do desc 'The line to be appended to the file located by the path parameter.' end diff --git a/spec/functions/ensure_resource_spec.rb b/spec/functions/ensure_resource_spec.rb index 611666e..2e8aefc 100644 --- a/spec/functions/ensure_resource_spec.rb +++ b/spec/functions/ensure_resource_spec.rb @@ -4,17 +4,16 @@ require 'spec_helper' require 'rspec-puppet' describe 'ensure_resource' do describe 'when a type or title is not specified' do - it do - should run.with_params().and_raise_error(ArgumentError) - should run.with_params(['type']).and_raise_error(ArgumentError) - end + it { should run.with_params().and_raise_error(ArgumentError) } + it { should run.with_params(['type']).and_raise_error(ArgumentError) } end + describe 'when compared against a resource with no attributes' do let :pre_condition do 'user { "dan": }' end - it do - should run.with_params('user', 'dan', {}) + it "should contain the the ensured resources" do + subject.should run.with_params('user', 'dan', {}) compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' end end @@ -23,18 +22,43 @@ describe 'ensure_resource' do let :pre_condition do 'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}' end - it do - # these first three should not fail - should run.with_params('User', 'dan', {}) - should run.with_params('User', 'dan', '') - should run.with_params('User', 'dan', {'ensure' => 'present'}) - should run.with_params('User', 'dan', - {'ensure' => 'present', 'managehome' => false} - ) - # test that this fails - should run.with_params('User', 'dan', - {'ensure' => 'absent', 'managehome' => false} - ).and_raise_error(Puppet::Error) + # these first three should not fail + it { should run.with_params('User', 'dan', {}) } + it { should run.with_params('User', 'dan', '') } + it { should run.with_params('User', 'dan', {'ensure' => 'present'}) } + it { should run.with_params('User', 'dan', {'ensure' => 'present', 'managehome' => false}) } + # test that this fails + it { should run.with_params('User', 'dan', {'ensure' => 'absent', 'managehome' => false}).and_raise_error(Puppet::Error) } + end + + describe 'when an array of new resources are passed in' do + it "should contain the ensured resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when an array of existing resources is compared against existing resources' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' + end + it "should return the existing resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when compared against existing resources with attributes' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' end + # These should not fail + it { should run.with_params('User', ['dan', 'alex'], {}) } + it { should run.with_params('User', ['dan', 'alex'], '') } + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'present'}) } + # This should fail + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'absent'}).and_raise_error(Puppet::Error) } end end diff --git a/spec/unit/facter/pe_required_facts_spec.rb b/spec/unit/facter/pe_required_facts_spec.rb new file mode 100644 index 0000000..f219b37 --- /dev/null +++ b/spec/unit/facter/pe_required_facts_spec.rb @@ -0,0 +1,69 @@ +# Puppet Enterprise requires the following facts to be set in order to operate. +# These facts are set using the file ???? and the two facts are +# `fact_stomp_port`, and `fact_stomp_server`. +# + +require 'spec_helper' + +describe "External facts in /etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt" do + context "With Facter 1.6.17 which does not have external facts support" do + before :each do + Facter.stubs(:version).returns("1.6.17") + # Stub out the filesystem for stdlib + Dir.stubs(:entries).with("/etc/puppetlabs/facter/facts.d"). + returns(['puppet_enterprise_installer.txt']) + Dir.stubs(:entries).with("/etc/facter/facts.d").returns([]) + File.stubs(:readlines).with('/etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt'). + returns([ + "fact_stomp_port=61613\n", + "fact_stomp_server=puppetmaster.acme.com\n", + "fact_is_puppetagent=true\n", + "fact_is_puppetmaster=false\n", + "fact_is_puppetca=false\n", + "fact_is_puppetconsole=false\n", + ]) + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + + it 'defines fact_stomp_port' do + Facter.fact(:fact_stomp_port).value.should == '61613' + end + it 'defines fact_stomp_server' do + Facter.fact(:fact_stomp_server).value.should == 'puppetmaster.acme.com' + end + it 'defines fact_is_puppetagent' do + Facter.fact(:fact_is_puppetagent).value.should == 'true' + end + it 'defines fact_is_puppetmaster' do + Facter.fact(:fact_is_puppetmaster).value.should == 'false' + end + it 'defines fact_is_puppetca' do + Facter.fact(:fact_is_puppetca).value.should == 'false' + end + it 'defines fact_is_puppetconsole' do + Facter.fact(:fact_is_puppetconsole).value.should == 'false' + end + end + + [ '1.7.1', '2.0.1' ].each do |v| + context "With Facter #{v} which has external facts support" do + before :each do + Facter.stubs(:version).returns(v) + end + + it 'does not call Facter::Util::DotD.new' do + Facter::Util::DotD.expects(:new).never + + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + end + end +end diff --git a/spec/unit/puppet/parser/functions/base64_spec.rb b/spec/unit/puppet/parser/functions/base64_spec.rb new file mode 100755 index 0000000..5faa5e6 --- /dev/null +++ b/spec/unit/puppet/parser/functions/base64_spec.rb @@ -0,0 +1,34 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the base64 function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("base64").should == "function_base64" + end + + it "should raise a ParseError if there are other than 2 arguments" do + expect { scope.function_base64([]) }.to(raise_error(Puppet::ParseError)) + expect { scope.function_base64(["asdf"]) }.to(raise_error(Puppet::ParseError)) + expect { scope.function_base64(["asdf","moo","cow"]) }.to(raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if argument 1 isn't 'encode' or 'decode'" do + expect { scope.function_base64(["bees","astring"]) }.to(raise_error(Puppet::ParseError, /first argument must be one of/)) + end + + it "should raise a ParseError if argument 2 isn't a string" do + expect { scope.function_base64(["encode",["2"]]) }.to(raise_error(Puppet::ParseError, /second argument must be a string/)) + end + + it "should encode a encoded string" do + result = scope.function_base64(["encode",'thestring']) + result.should =~ /\AdGhlc3RyaW5n\n\Z/ + end + it "should decode a base64 encoded string" do + result = scope.function_base64(["decode",'dGhlc3RyaW5n']) + result.should == 'thestring' + end +end diff --git a/spec/unit/puppet/parser/functions/delete_undef_values_spec.rb b/spec/unit/puppet/parser/functions/delete_undef_values_spec.rb new file mode 100644 index 0000000..0536641 --- /dev/null +++ b/spec/unit/puppet/parser/functions/delete_undef_values_spec.rb @@ -0,0 +1,29 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the delete_undef_values function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("delete_undef_values").should == "function_delete_undef_values" + end + + it "should raise a ParseError if there is less than 1 argument" do + lambda { scope.function_delete_undef_values([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if the argument is not Array nor Hash" do + lambda { scope.function_delete_undef_values(['']) }.should( raise_error(Puppet::ParseError)) + lambda { scope.function_delete_undef_values([nil]) }.should( raise_error(Puppet::ParseError)) + end + + it "should delete all undef items from Array and only these" do + result = scope.function_delete_undef_values([['a',:undef,'c','undef']]) + result.should(eq(['a','c','undef'])) + end + + it "should delete all undef items from Hash and only these" do + result = scope.function_delete_undef_values([{'a'=>'A','b'=>:undef,'c'=>'C','d'=>'undef'}]) + result.should(eq({'a'=>'A','c'=>'C','d'=>'undef'})) + end +end diff --git a/spec/unit/puppet/parser/functions/delete_values_spec.rb b/spec/unit/puppet/parser/functions/delete_values_spec.rb new file mode 100644 index 0000000..e15c366 --- /dev/null +++ b/spec/unit/puppet/parser/functions/delete_values_spec.rb @@ -0,0 +1,30 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the delete_values function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("delete_values").should == "function_delete_values" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_delete_values([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if there are greater than 2 arguments" do + lambda { scope.function_delete([[], 'foo', 'bar']) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a TypeError if the argument is not a hash" do + lambda { scope.function_delete_values([1,'bar']) }.should( raise_error(TypeError)) + lambda { scope.function_delete_values(['foo','bar']) }.should( raise_error(TypeError)) + lambda { scope.function_delete_values([[],'bar']) }.should( raise_error(TypeError)) + end + + it "should delete all instances of a value from a hash" do + result = scope.function_delete_values([{ 'a'=>'A', 'b'=>'B', 'B'=>'C', 'd'=>'B' },'B']) + result.should(eq({ 'a'=>'A', 'B'=>'C' })) + end + +end diff --git a/spec/unit/puppet/parser/functions/difference_spec.rb b/spec/unit/puppet/parser/functions/difference_spec.rb new file mode 100644 index 0000000..9feff09 --- /dev/null +++ b/spec/unit/puppet/parser/functions/difference_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the difference function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("difference").should == "function_difference" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_difference([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should return the difference between two arrays" do + result = scope.function_difference([["a","b","c"],["b","c","d"]]) + result.should(eq(["a"])) + end +end diff --git a/spec/unit/puppet/parser/functions/dirname_spec.rb b/spec/unit/puppet/parser/functions/dirname_spec.rb new file mode 100755 index 0000000..fb3b4fe --- /dev/null +++ b/spec/unit/puppet/parser/functions/dirname_spec.rb @@ -0,0 +1,24 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the dirname function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("dirname").should == "function_dirname" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_dirname([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return dirname for an absolute path" do + result = scope.function_dirname(['/path/to/a/file.ext']) + result.should(eq('/path/to/a')) + end + + it "should return dirname for a relative path" do + result = scope.function_dirname(['path/to/a/file.ext']) + result.should(eq('path/to/a')) + end +end diff --git a/spec/unit/puppet/parser/functions/intersection_spec.rb b/spec/unit/puppet/parser/functions/intersection_spec.rb new file mode 100644 index 0000000..fd44f7f --- /dev/null +++ b/spec/unit/puppet/parser/functions/intersection_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the intersection function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("intersection").should == "function_intersection" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_intersection([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should return the intersection of two arrays" do + result = scope.function_intersection([["a","b","c"],["b","c","d"]]) + result.should(eq(["b","c"])) + end +end diff --git a/spec/unit/puppet/parser/functions/range_spec.rb b/spec/unit/puppet/parser/functions/range_spec.rb index 42751f4..0e1ad37 100644 --- a/spec/unit/puppet/parser/functions/range_spec.rb +++ b/spec/unit/puppet/parser/functions/range_spec.rb @@ -4,31 +4,67 @@ require 'spec_helper' describe "the range function" do let(:scope) { PuppetlabsSpec::PuppetInternals.scope } - it "should exist" do + it "exists" do Puppet::Parser::Functions.function("range").should == "function_range" end - it "should raise a ParseError if there is less than 1 arguments" do - lambda { scope.function_range([]) }.should( raise_error(Puppet::ParseError)) + it "raises a ParseError if there is less than 1 arguments" do + expect { scope.function_range([]) }.to raise_error Puppet::ParseError, /Wrong number of arguments.*0 for 1/ end - it "should return a letter range" do - result = scope.function_range(["a","d"]) - result.should(eq(['a','b','c','d'])) - end + describe 'with a letter range' do + it "returns a letter range" do + result = scope.function_range(["a","d"]) + result.should eq ['a','b','c','d'] + end + + it "returns a letter range given a step of 1" do + result = scope.function_range(["a","d","1"]) + result.should eq ['a','b','c','d'] + end - it "should return a number range" do - result = scope.function_range(["1","4"]) - result.should(eq([1,2,3,4])) + it "returns a stepped letter range" do + result = scope.function_range(["a","d","2"]) + result.should eq ['a','c'] + end + + it "returns a stepped letter range given a negative step" do + result = scope.function_range(["a","d","-2"]) + result.should eq ['a','c'] + end end - it "should work with padded hostname like strings" do - expected = ("host01".."host10").to_a - scope.function_range(["host01","host10"]).should eq expected + describe 'with a number range' do + it "returns a number range" do + result = scope.function_range(["1","4"]) + result.should eq [1,2,3,4] + end + + it "returns a number range given a step of 1" do + result = scope.function_range(["1","4","1"]) + result.should eq [1,2,3,4] + end + + it "returns a stepped number range" do + result = scope.function_range(["1","4","2"]) + result.should eq [1,3] + end + + it "returns a stepped number range given a negative step" do + result = scope.function_range(["1","4","-2"]) + result.should eq [1,3] + end end - it "should coerce zero padded digits to integers" do - expected = (0..10).to_a - scope.function_range(["00", "10"]).should eq expected + describe 'with a numeric-like string range' do + it "works with padded hostname like strings" do + expected = ("host01".."host10").to_a + scope.function_range(["host01","host10"]).should eq expected + end + + it "coerces zero padded digits to integers" do + expected = (0..10).to_a + scope.function_range(["00", "10"]).should eq expected + end end end diff --git a/spec/unit/puppet/parser/functions/union_spec.rb b/spec/unit/puppet/parser/functions/union_spec.rb new file mode 100644 index 0000000..0d282ca --- /dev/null +++ b/spec/unit/puppet/parser/functions/union_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the union function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("union").should == "function_union" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_union([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should join two arrays together" do + result = scope.function_union([["a","b","c"],["b","c","d"]]) + result.should(eq(["a","b","c","d"])) + end +end diff --git a/spec/unit/puppet/parser/functions/uriescape_spec.rb b/spec/unit/puppet/parser/functions/uriescape_spec.rb index 371de46..7211c88 100644 --- a/spec/unit/puppet/parser/functions/uriescape_spec.rb +++ b/spec/unit/puppet/parser/functions/uriescape_spec.rb @@ -13,8 +13,8 @@ describe "the uriescape function" do end it "should uriescape a string" do - result = scope.function_uriescape([":/?#[]@!$&'()*+,;= "]) - result.should(eq('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D%20')) + result = scope.function_uriescape([":/?#[]@!$&'()*+,;= \"{}"]) + result.should(eq(':/?%23[]@!$&\'()*+,;=%20%22%7B%7D')) end it "should do nothing if a string is already safe" do diff --git a/spec/unit/puppet/parser/functions/validate_ipv4_address_spec.rb b/spec/unit/puppet/parser/functions/validate_ipv4_address_spec.rb new file mode 100644 index 0000000..85536d3 --- /dev/null +++ b/spec/unit/puppet/parser/functions/validate_ipv4_address_spec.rb @@ -0,0 +1,64 @@ +#! /usr/bin/env/ruby -S rspec + +require "spec_helper" + +describe Puppet::Parser::Functions.function(:validate_ipv4_address) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + describe "when calling validate_ipv4_address from puppet" do + describe "when given IPv4 address strings" do + it "should compile with one argument" do + Puppet[:code] = "validate_ipv4_address('1.2.3.4')" + scope.compiler.compile + end + + it "should compile with multiple arguments" do + Puppet[:code] = "validate_ipv4_address('1.2.3.4', '5.6.7.8')" + scope.compiler.compile + end + end + + describe "when given an IPv6 address" do + it "should not compile" do + Puppet[:code] = "validate_ipv4_address('3ffe:505')" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /not a valid IPv4 address/) + end + end + + describe "when given other strings" do + it "should not compile" do + Puppet[:code] = "validate_ipv4_address('hello', 'world')" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /not a valid IPv4 address/) + end + end + + describe "when given numbers" do + it "should not compile" do + Puppet[:code] = "validate_ipv4_address(1, 2)" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /is not a valid IPv4 address/) + end + end + + describe "when given booleans" do + it "should not compile" do + Puppet[:code] = "validate_ipv4_address(true, false)" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /is not a string/) + end + end + + it "should not compile when no arguments are passed" do + Puppet[:code] = "validate_ipv4_address()" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /wrong number of arguments/) + end + end +end diff --git a/spec/unit/puppet/parser/functions/validate_ipv6_address_spec.rb b/spec/unit/puppet/parser/functions/validate_ipv6_address_spec.rb new file mode 100644 index 0000000..1fe5304 --- /dev/null +++ b/spec/unit/puppet/parser/functions/validate_ipv6_address_spec.rb @@ -0,0 +1,67 @@ +#! /usr/bin/env/ruby -S rspec + +require "spec_helper" + +describe Puppet::Parser::Functions.function(:validate_ipv6_address) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + describe "when calling validate_ipv6_address from puppet" do + describe "when given IPv6 address strings" do + it "should compile with one argument" do + Puppet[:code] = "validate_ipv6_address('3ffe:0505:0002::')" + scope.compiler.compile + end + + it "should compile with multiple arguments" do + Puppet[:code] = "validate_ipv6_address('3ffe:0505:0002::', '3ffe:0505:0001::')" + scope.compiler.compile + end + end + + describe "when given an ipv4 address" do + it "should not compile" do + Puppet[:code] = "validate_ipv6_address('1.2.3.4')" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/) + end + end + + describe "when given other strings" do + it "should not compile" do + Puppet[:code] = "validate_ipv6_address('hello', 'world')" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/) + end + end + + # 1.8.7 is EOL'd and also absolutely insane about ipv6 + unless RUBY_VERSION == '1.8.7' + describe "when given numbers" do + it "should not compile" do + Puppet[:code] = "validate_ipv6_address(1, 2)" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/) + end + end + end + + describe "when given booleans" do + it "should not compile" do + Puppet[:code] = "validate_ipv6_address(true, false)" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /is not a string/) + end + end + + it "should not compile when no arguments are passed" do + Puppet[:code] = "validate_ipv6_address()" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, /wrong number of arguments/) + end + end +end diff --git a/spec/unit/puppet/parser/functions/validate_slength_spec.rb b/spec/unit/puppet/parser/functions/validate_slength_spec.rb index a870c63..6ed1b0f 100755 --- a/spec/unit/puppet/parser/functions/validate_slength_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_slength_spec.rb @@ -47,7 +47,7 @@ describe "the validate_slength function" do end it "should fail if you pass something other than a string or array" do - expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError), /please pass a string, or an array of strings/) + expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError, /please pass a string, or an array of strings/)) end it "should not fail if string is smaller or equal to size" do diff --git a/spec/unit/puppet/provider/file_line/ruby_spec.rb b/spec/unit/puppet/provider/file_line/ruby_spec.rb index 7857d39..648c05b 100644 --- a/spec/unit/puppet/provider/file_line/ruby_spec.rb +++ b/spec/unit/puppet/provider/file_line/ruby_spec.rb @@ -61,6 +61,39 @@ describe provider_class do File.read(@tmpfile).should eql("foo1\nfoo=blah\nfoo2\nfoo=baz") end + it 'should replace all lines that matches' do + @resource = Puppet::Type::File_line.new( + { + :name => 'foo', + :path => @tmpfile, + :line => 'foo = bar', + :match => '^foo\s*=.*$', + :multiple => true + } + ) + @provider = provider_class.new(@resource) + File.open(@tmpfile, 'w') do |fh| + fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz") + end + @provider.exists?.should be_nil + @provider.create + File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2\nfoo = bar") + end + + it 'should raise an error with invalid values' do + expect { + @resource = Puppet::Type::File_line.new( + { + :name => 'foo', + :path => @tmpfile, + :line => 'foo = bar', + :match => '^foo\s*=.*$', + :multiple => 'asgadga' + } + ) + }.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./) + end + it 'should replace a line that matches' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo=blah\nfoo2") |