summaryrefslogtreecommitdiff
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/functions/type_of.rb17
-rw-r--r--lib/puppet/parser/functions/assert_private.rb29
-rw-r--r--lib/puppet/parser/functions/basename.rb34
-rw-r--r--lib/puppet/parser/functions/bool2num.rb25
-rw-r--r--lib/puppet/parser/functions/capitalize.rb3
-rw-r--r--lib/puppet/parser/functions/ceiling.rb25
-rw-r--r--lib/puppet/parser/functions/chomp.rb3
-rw-r--r--lib/puppet/parser/functions/chop.rb3
-rw-r--r--lib/puppet/parser/functions/concat.rb18
-rw-r--r--lib/puppet/parser/functions/delete.rb27
-rw-r--r--lib/puppet/parser/functions/dirname.rb14
-rw-r--r--lib/puppet/parser/functions/downcase.rb3
-rw-r--r--lib/puppet/parser/functions/empty.rb3
-rw-r--r--lib/puppet/parser/functions/ensure_resource.rb3
-rw-r--r--lib/puppet/parser/functions/fqdn_rand_string.rb34
-rw-r--r--lib/puppet/parser/functions/fqdn_rotate.rb19
-rw-r--r--lib/puppet/parser/functions/getvar.rb5
-rw-r--r--lib/puppet/parser/functions/has_interface_with.rb20
-rw-r--r--lib/puppet/parser/functions/is_domain_name.rb12
-rw-r--r--lib/puppet/parser/functions/lstrip.rb3
-rw-r--r--lib/puppet/parser/functions/member.rb24
-rw-r--r--lib/puppet/parser/functions/prefix.rb23
-rw-r--r--lib/puppet/parser/functions/private.rb24
-rw-r--r--lib/puppet/parser/functions/pw_hash.rb56
-rw-r--r--lib/puppet/parser/functions/range.rb26
-rw-r--r--lib/puppet/parser/functions/reverse.rb3
-rw-r--r--lib/puppet/parser/functions/rstrip.rb3
-rw-r--r--lib/puppet/parser/functions/shuffle.rb3
-rw-r--r--lib/puppet/parser/functions/strip.rb3
-rw-r--r--lib/puppet/parser/functions/swapcase.rb3
-rw-r--r--lib/puppet/parser/functions/to_bytes.rb5
-rw-r--r--lib/puppet/parser/functions/type.rb43
-rw-r--r--lib/puppet/parser/functions/type3x.rb51
-rw-r--r--lib/puppet/parser/functions/unique.rb3
-rw-r--r--lib/puppet/parser/functions/upcase.rb18
-rw-r--r--lib/puppet/parser/functions/uriescape.rb5
-rw-r--r--lib/puppet/parser/functions/validate_absolute_path.rb61
-rw-r--r--lib/puppet/parser/functions/validate_augeas.rb2
-rw-r--r--lib/puppet/parser/functions/validate_cmd.rb25
-rw-r--r--lib/puppet/parser/functions/validate_integer.rb131
-rw-r--r--lib/puppet/parser/functions/validate_numeric.rb93
-rw-r--r--lib/puppet/parser/functions/validate_string.rb11
-rw-r--r--lib/puppet/parser/functions/values_at.rb1
-rw-r--r--lib/puppet/parser/functions/zip.rb28
-rw-r--r--lib/puppet/provider/file_line/ruby.rb24
-rw-r--r--lib/puppet/type/file_line.rb37
46 files changed, 755 insertions, 251 deletions
diff --git a/lib/puppet/functions/type_of.rb b/lib/puppet/functions/type_of.rb
new file mode 100644
index 0000000..02cdd4d
--- /dev/null
+++ b/lib/puppet/functions/type_of.rb
@@ -0,0 +1,17 @@
+# Returns the type when passed a value.
+#
+# @example how to compare values' types
+# # compare the types of two values
+# if type_of($first_value) != type_of($second_value) { fail("first_value and second_value are different types") }
+# @example how to compare against an abstract type
+# unless type_of($first_value) <= Numeric { fail("first_value must be Numeric") }
+# unless type_of{$first_value) <= Collection[1] { fail("first_value must be an Array or Hash, and contain at least one element") }
+#
+# See the documentation for "The Puppet Type System" for more information about types.
+# See the `assert_type()` function for flexible ways to assert the type of a value.
+#
+Puppet::Functions.create_function(:type_of) do
+ def type_of(value)
+ Puppet::Pops::Types::TypeCalculator.infer_set(value)
+ end
+end
diff --git a/lib/puppet/parser/functions/assert_private.rb b/lib/puppet/parser/functions/assert_private.rb
new file mode 100644
index 0000000..66c79cc
--- /dev/null
+++ b/lib/puppet/parser/functions/assert_private.rb
@@ -0,0 +1,29 @@
+#
+# assert_private.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:assert_private, :doc => <<-'EOS'
+ Sets the current class or definition as private.
+ Calling the class or definition from outside the current module will fail.
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "assert_private(): Wrong number of arguments "+
+ "given (#{args.size}}) for 0 or 1)") if args.size > 1
+
+ scope = self
+ if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name')
+ message = nil
+ if args[0] and args[0].is_a? String
+ message = args[0]
+ else
+ manifest_name = scope.source.name
+ manifest_type = scope.source.type
+ message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition'
+ message += " #{manifest_name} is private"
+ end
+ raise(Puppet::ParseError, message)
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/basename.rb b/lib/puppet/parser/functions/basename.rb
new file mode 100644
index 0000000..f7e4438
--- /dev/null
+++ b/lib/puppet/parser/functions/basename.rb
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+ newfunction(:basename, :type => :rvalue, :doc => <<-EOS
+ Strips directory (and optional suffix) from a filename
+ EOS
+ ) do |arguments|
+
+ if arguments.size < 1 then
+ raise(Puppet::ParseError, "basename(): No arguments given")
+ elsif arguments.size > 2 then
+ raise(Puppet::ParseError, "basename(): Too many arguments given (#{arguments.size})")
+ else
+
+ unless arguments[0].is_a?(String)
+ raise(Puppet::ParseError, 'basename(): Requires string as first argument')
+ end
+
+ if arguments.size == 1 then
+ rv = File.basename(arguments[0])
+ elsif arguments.size == 2 then
+
+ unless arguments[1].is_a?(String)
+ raise(Puppet::ParseError, 'basename(): Requires string as second argument')
+ end
+
+ rv = File.basename(arguments[0], arguments[1])
+ end
+
+ end
+
+ return rv
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/bool2num.rb b/lib/puppet/parser/functions/bool2num.rb
index 9a07a8a..6ad6cf4 100644
--- a/lib/puppet/parser/functions/bool2num.rb
+++ b/lib/puppet/parser/functions/bool2num.rb
@@ -14,30 +14,7 @@ module Puppet::Parser::Functions
raise(Puppet::ParseError, "bool2num(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
- value = arguments[0]
- klass = value.class
-
- # We can have either true or false, or string which resembles boolean ...
- unless [FalseClass, TrueClass, String].include?(klass)
- raise(Puppet::ParseError, 'bool2num(): Requires either ' +
- 'boolean or string to work with')
- end
-
- if value.is_a?(String)
- # We consider all the yes, no, y, n and so on too ...
- value = case value
- #
- # This is how undef looks like in Puppet ...
- # We yield 0 (or false if you wish) in this case.
- #
- when /^$/, '' then false # Empty string will be false ...
- when /^(1|t|y|true|yes)$/ then true
- when /^(0|f|n|false|no)$/ then false
- when /^(undef|undefined)$/ then false # This is not likely to happen ...
- else
- raise(Puppet::ParseError, 'bool2num(): Unknown type of boolean given')
- end
- end
+ value = function_str2bool([arguments[0]])
# We have real boolean values as well ...
result = value ? 1 : 0
diff --git a/lib/puppet/parser/functions/capitalize.rb b/lib/puppet/parser/functions/capitalize.rb
index 640d00b..98b2d16 100644
--- a/lib/puppet/parser/functions/capitalize.rb
+++ b/lib/puppet/parser/functions/capitalize.rb
@@ -13,9 +13,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'capitalize(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/ceiling.rb b/lib/puppet/parser/functions/ceiling.rb
new file mode 100644
index 0000000..5f3b10b
--- /dev/null
+++ b/lib/puppet/parser/functions/ceiling.rb
@@ -0,0 +1,25 @@
+module Puppet::Parser::Functions
+ newfunction(:ceiling, :type => :rvalue, :doc => <<-EOS
+ Returns the smallest integer greater or equal to the argument.
+ Takes a single numeric value as an argument.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "ceiling(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size != 1
+
+ begin
+ arg = Float(arguments[0])
+ rescue TypeError, ArgumentError => e
+ raise(Puppet::ParseError, "ceiling(): Wrong argument type " +
+ "given (#{arguments[0]} for Numeric)")
+ end
+
+ raise(Puppet::ParseError, "ceiling(): Wrong argument type " +
+ "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false
+
+ arg.ceil
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/chomp.rb b/lib/puppet/parser/functions/chomp.rb
index 4564a00..c55841e 100644
--- a/lib/puppet/parser/functions/chomp.rb
+++ b/lib/puppet/parser/functions/chomp.rb
@@ -14,9 +14,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'chomp(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/chop.rb b/lib/puppet/parser/functions/chop.rb
index f242af3..b24ab78 100644
--- a/lib/puppet/parser/functions/chop.rb
+++ b/lib/puppet/parser/functions/chop.rb
@@ -16,9 +16,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'chop(): Requires either an ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/concat.rb b/lib/puppet/parser/functions/concat.rb
index 0d35b07..618e62d 100644
--- a/lib/puppet/parser/functions/concat.rb
+++ b/lib/puppet/parser/functions/concat.rb
@@ -4,31 +4,35 @@
module Puppet::Parser::Functions
newfunction(:concat, :type => :rvalue, :doc => <<-EOS
-Appends the contents of array 2 onto array 1.
+Appends the contents of multiple arrays into array 1.
*Example:*
- concat(['1','2','3'],['4','5','6'])
+ concat(['1','2','3'],['4','5','6'],['7','8','9'])
Would result in:
- ['1','2','3','4','5','6']
+ ['1','2','3','4','5','6','7','8','9']
EOS
) do |arguments|
- # Check that 2 arguments have been given ...
+ # Check that more than 2 arguments have been given ...
raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
- "given (#{arguments.size} for 2)") if arguments.size != 2
+ "given (#{arguments.size} for < 2)") if arguments.size < 2
a = arguments[0]
- b = arguments[1]
# Check that the first parameter is an array
unless a.is_a?(Array)
raise(Puppet::ParseError, 'concat(): Requires array to work with')
end
- result = a + Array(b)
+ result = a
+ arguments.shift
+
+ arguments.each do |x|
+ result = result + Array(x)
+ end
return result
end
diff --git a/lib/puppet/parser/functions/delete.rb b/lib/puppet/parser/functions/delete.rb
index d03a293..f548b44 100644
--- a/lib/puppet/parser/functions/delete.rb
+++ b/lib/puppet/parser/functions/delete.rb
@@ -17,27 +17,30 @@ string, or key from a hash.
delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
Would return: {'a'=>1,'c'=>3}
+ delete({'a'=>1,'b'=>2,'c'=>3}, ['b','c'])
+ Would return: {'a'=>1}
+
delete('abracadabra', 'bra')
Would return: 'acada'
- EOS
+ EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
- "given #{arguments.size} for 2.")
+ "given #{arguments.size} for 2.")
end
collection = arguments[0].dup
- item = arguments[1]
-
- case collection
- when Array, Hash
- collection.delete item
- when String
- collection.gsub! item, ''
- else
- raise(TypeError, "delete(): First argument must be an Array, " +
- "String, or Hash. Given an argument of class #{collection.class}.")
+ Array(arguments[1]).each do |item|
+ case collection
+ when Array, Hash
+ collection.delete item
+ when String
+ collection.gsub! item, ''
+ else
+ raise(TypeError, "delete(): First argument must be an Array, " +
+ "String, or Hash. Given an argument of class #{collection.class}.")
+ end
end
collection
end
diff --git a/lib/puppet/parser/functions/dirname.rb b/lib/puppet/parser/functions/dirname.rb
index ea8cc1e..40b300d 100644
--- a/lib/puppet/parser/functions/dirname.rb
+++ b/lib/puppet/parser/functions/dirname.rb
@@ -4,11 +4,17 @@ module Puppet::Parser::Functions
EOS
) do |arguments|
- raise(Puppet::ParseError, "dirname(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
+ if arguments.size < 1 then
+ raise(Puppet::ParseError, "dirname(): No arguments given")
+ end
+ if arguments.size > 1 then
+ raise(Puppet::ParseError, "dirname(): Too many arguments given (#{arguments.size})")
+ end
+ unless arguments[0].is_a?(String)
+ raise(Puppet::ParseError, 'dirname(): Requires string as argument')
+ end
- path = arguments[0]
- return File.dirname(path)
+ return File.dirname(arguments[0])
end
end
diff --git a/lib/puppet/parser/functions/downcase.rb b/lib/puppet/parser/functions/downcase.rb
index 4066d21..040b84f 100644
--- a/lib/puppet/parser/functions/downcase.rb
+++ b/lib/puppet/parser/functions/downcase.rb
@@ -12,9 +12,8 @@ Converts the case of a string or all strings in an array to lower case.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'downcase(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/empty.rb b/lib/puppet/parser/functions/empty.rb
index 80ebb86..cca620f 100644
--- a/lib/puppet/parser/functions/empty.rb
+++ b/lib/puppet/parser/functions/empty.rb
@@ -12,9 +12,8 @@ Returns true if the variable is empty.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, Hash, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String)
raise(Puppet::ParseError, 'empty(): Requires either ' +
'array, hash or string to work with')
end
diff --git a/lib/puppet/parser/functions/ensure_resource.rb b/lib/puppet/parser/functions/ensure_resource.rb
index 05e5593..1ba6a44 100644
--- a/lib/puppet/parser/functions/ensure_resource.rb
+++ b/lib/puppet/parser/functions/ensure_resource.rb
@@ -36,8 +36,9 @@ ENDOFDOC
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")
+ Puppet.debug("Resource #{type}[#{item}] with params #{params} not created because it already exists")
else
+ Puppet.debug("Create new resource #{type}[#{item}] with params #{params}")
Puppet::Parser::Functions.function(:create_resources)
function_create_resources([type.capitalize, { item => params }])
end
diff --git a/lib/puppet/parser/functions/fqdn_rand_string.rb b/lib/puppet/parser/functions/fqdn_rand_string.rb
new file mode 100644
index 0000000..785c9fd
--- /dev/null
+++ b/lib/puppet/parser/functions/fqdn_rand_string.rb
@@ -0,0 +1,34 @@
+Puppet::Parser::Functions::newfunction(
+ :fqdn_rand_string,
+ :arity => -2,
+ :type => :rvalue,
+ :doc => "Usage: `fqdn_rand_string(LENGTH, [CHARSET], [SEED])`. LENGTH is
+ required and must be a positive integer. CHARSET is optional and may be
+ `undef` or a string. SEED is optional and may be any number or string.
+
+ Generates a random string LENGTH characters long using the character set
+ provided by CHARSET, combining the `$fqdn` fact and the value of SEED for
+ repeatable randomness. (That is, each node will get a different random
+ string from this function, but a given node's result will be the same every
+ time unless its hostname changes.) Adding a SEED can be useful if you need
+ more than one unrelated string. CHARSET will default to alphanumeric if
+ `undef` or an empty string.") do |args|
+ raise(ArgumentError, "fqdn_rand_string(): wrong number of arguments (0 for 1)") if args.size == 0
+ Puppet::Parser::Functions.function('is_integer')
+ raise(ArgumentError, "fqdn_rand_base64(): first argument must be a positive integer") unless function_is_integer([args[0]]) and args[0].to_i > 0
+ raise(ArgumentError, "fqdn_rand_base64(): second argument must be undef or a string") unless args[1].nil? or args[1].is_a? String
+
+ Puppet::Parser::Functions.function('fqdn_rand')
+
+ length = args.shift.to_i
+ charset = args.shift.to_s.chars.to_a
+
+ charset = (0..9).map { |i| i.to_s } + ('A'..'Z').to_a + ('a'..'z').to_a if charset.empty?
+
+ rand_string = ''
+ for current in 1..length
+ rand_string << charset[function_fqdn_rand([charset.size, (args + [current.to_s]).join(':')]).to_i]
+ end
+
+ rand_string
+end
diff --git a/lib/puppet/parser/functions/fqdn_rotate.rb b/lib/puppet/parser/functions/fqdn_rotate.rb
index 6558206..cf22d36 100644
--- a/lib/puppet/parser/functions/fqdn_rotate.rb
+++ b/lib/puppet/parser/functions/fqdn_rotate.rb
@@ -12,10 +12,9 @@ Rotates an array a random number of times based on a nodes fqdn.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
require 'digest/md5'
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
'array or string to work with')
end
@@ -32,8 +31,20 @@ Rotates an array a random number of times based on a nodes fqdn.
elements = result.size
- srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
- rand(elements).times {
+ seed = Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex
+ # deterministic_rand() was added in Puppet 3.2.0; reimplement if necessary
+ if Puppet::Util.respond_to?(:deterministic_rand)
+ offset = Puppet::Util.deterministic_rand(seed, elements).to_i
+ else
+ if defined?(Random) == 'constant' && Random.class == Class
+ offset = Random.new(seed).rand(elements)
+ else
+ srand(seed)
+ offset = rand(elements)
+ srand()
+ end
+ end
+ offset.times {
result.push result.shift
}
diff --git a/lib/puppet/parser/functions/getvar.rb b/lib/puppet/parser/functions/getvar.rb
index 1621149..fb336b6 100644
--- a/lib/puppet/parser/functions/getvar.rb
+++ b/lib/puppet/parser/functions/getvar.rb
@@ -19,7 +19,10 @@ module Puppet::Parser::Functions
raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
end
- self.lookupvar("#{args[0]}")
+ begin
+ self.lookupvar("#{args[0]}")
+ rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
+ end
end
diff --git a/lib/puppet/parser/functions/has_interface_with.rb b/lib/puppet/parser/functions/has_interface_with.rb
index 927b0df..3691524 100644
--- a/lib/puppet/parser/functions/has_interface_with.rb
+++ b/lib/puppet/parser/functions/has_interface_with.rb
@@ -35,13 +35,29 @@ has_interface_with("lo") => true
kind, value = args
- if lookupvar(kind) == value
+ # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
+ # https://tickets.puppetlabs.com/browse/PUP-3597
+ factval = nil
+ catch :undefined_variable do
+ factval = lookupvar(kind)
+ end
+ if factval == value
return true
end
result = false
interfaces.each do |iface|
- if value == lookupvar("#{kind}_#{iface}")
+ iface.downcase!
+ factval = nil
+ begin
+ # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
+ # https://tickets.puppetlabs.com/browse/PUP-3597
+ catch :undefined_variable do
+ factval = lookupvar("#{kind}_#{iface}")
+ end
+ rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
+ end
+ if value == factval
result = true
break
end
diff --git a/lib/puppet/parser/functions/is_domain_name.rb b/lib/puppet/parser/functions/is_domain_name.rb
index b3fee96..90ede32 100644
--- a/lib/puppet/parser/functions/is_domain_name.rb
+++ b/lib/puppet/parser/functions/is_domain_name.rb
@@ -13,16 +13,16 @@ Returns true if the string passed to this function is a syntactically correct do
"given #{arguments.size} for 1")
end
- domain = arguments[0]
+ # Only allow string types
+ return false unless arguments[0].is_a?(String)
+
+ domain = arguments[0].dup
# Limits (rfc1035, 3.1)
domain_max_length=255
label_min_length=1
label_max_length=63
- # Only allow string types
- return false unless domain.is_a?(String)
-
# Allow ".", it is the top level domain
return true if domain == '.'
@@ -33,6 +33,10 @@ Returns true if the string passed to this function is a syntactically correct do
return false if domain.empty?
return false if domain.length > domain_max_length
+ # The top level domain must be alphabetic if there are multiple labels.
+ # See rfc1123, 2.1
+ return false if domain.include? '.' and not /\.[A-Za-z]+$/.match(domain)
+
# Check each label in the domain
labels = domain.split('.')
vlabels = labels.each do |label|
diff --git a/lib/puppet/parser/functions/lstrip.rb b/lib/puppet/parser/functions/lstrip.rb
index 3a64de3..624e4c8 100644
--- a/lib/puppet/parser/functions/lstrip.rb
+++ b/lib/puppet/parser/functions/lstrip.rb
@@ -12,9 +12,8 @@ Strips leading spaces to the left of a string.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'lstrip(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/member.rb b/lib/puppet/parser/functions/member.rb
index 43d76af..88609ce 100644
--- a/lib/puppet/parser/functions/member.rb
+++ b/lib/puppet/parser/functions/member.rb
@@ -8,6 +8,7 @@
module Puppet::Parser::Functions
newfunction(:member, :type => :rvalue, :doc => <<-EOS
This function determines if a variable is a member of an array.
+The variable can be a string, fixnum, or array.
*Examples:*
@@ -15,9 +16,17 @@ This function determines if a variable is a member of an array.
Would return: true
+ member(['a', 'b', 'c'], ['a', 'b'])
+
+would return: true
+
member(['a','b'], 'c')
Would return: false
+
+ member(['a', 'b', 'c'], ['d', 'b'])
+
+would return: false
EOS
) do |arguments|
@@ -30,12 +39,21 @@ Would return: false
raise(Puppet::ParseError, 'member(): Requires array to work with')
end
- item = arguments[1]
+ unless arguments[1].is_a? String or arguments[1].is_a? Fixnum or arguments[1].is_a? Array
+ raise(Puppet::ParseError, 'member(): Item to search for must be a string, fixnum, or array')
+ end
+
+ if arguments[1].is_a? String or arguments[1].is_a? Fixnum
+ item = Array(arguments[1])
+ else
+ item = arguments[1]
+ end
+
raise(Puppet::ParseError, 'member(): You must provide item ' +
- 'to search for within array given') if item.empty?
+ 'to search for within array given') if item.respond_to?('empty?') && item.empty?
- result = array.include?(item)
+ result = (item - array).empty?
return result
end
diff --git a/lib/puppet/parser/functions/prefix.rb b/lib/puppet/parser/functions/prefix.rb
index d02286a..ac1c58a 100644
--- a/lib/puppet/parser/functions/prefix.rb
+++ b/lib/puppet/parser/functions/prefix.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
-This function applies a prefix to all elements in an array.
+This function applies a prefix to all elements in an array or a hash.
*Examples:*
@@ -18,10 +18,10 @@ Will return: ['pa','pb','pc']
raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
- array = arguments[0]
+ enumerable = arguments[0]
- unless array.is_a?(Array)
- raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
+ unless enumerable.is_a?(Array) or enumerable.is_a?(Hash)
+ raise Puppet::ParseError, "prefix(): expected first argument to be an Array or a Hash, got #{enumerable.inspect}"
end
prefix = arguments[1] if arguments[1]
@@ -32,10 +32,17 @@ Will return: ['pa','pb','pc']
end
end
- # Turn everything into string same as join would do ...
- result = array.collect do |i|
- i = i.to_s
- prefix ? prefix + i : i
+ if enumerable.is_a?(Array)
+ # Turn everything into string same as join would do ...
+ result = enumerable.collect do |i|
+ i = i.to_s
+ prefix ? prefix + i : i
+ end
+ else
+ result = Hash[enumerable.map do |k,v|
+ k = k.to_s
+ [ prefix ? prefix + k : k, v ]
+ end]
end
return result
diff --git a/lib/puppet/parser/functions/private.rb b/lib/puppet/parser/functions/private.rb
index 60210d3..3b00ba1 100644
--- a/lib/puppet/parser/functions/private.rb
+++ b/lib/puppet/parser/functions/private.rb
@@ -4,26 +4,14 @@
module Puppet::Parser::Functions
newfunction(:private, :doc => <<-'EOS'
- Sets the current class or definition as private.
+ DEPRECATED: Sets the current class or definition as private.
Calling the class or definition from outside the current module will fail.
- EOS
+ EOS
) do |args|
-
- raise(Puppet::ParseError, "private(): Wrong number of arguments "+
- "given (#{args.size}}) for 0 or 1)") if args.size > 1
-
- scope = self
- if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name')
- message = nil
- if args[0] and args[0].is_a? String
- message = args[0]
- else
- manifest_name = scope.source.name
- manifest_type = scope.source.type
- message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition'
- message += " #{manifest_name} is private"
- end
- raise(Puppet::ParseError, message)
+ warning("private() DEPRECATED: This function will cease to function on Puppet 4; please use assert_private() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.")
+ if !Puppet::Parser::Functions.autoloader.loaded?(:assert_private)
+ Puppet::Parser::Functions.autoloader.load(:assert_private)
end
+ function_assert_private([(args[0] unless args.size < 1)])
end
end
diff --git a/lib/puppet/parser/functions/pw_hash.rb b/lib/puppet/parser/functions/pw_hash.rb
new file mode 100644
index 0000000..ad3e393
--- /dev/null
+++ b/lib/puppet/parser/functions/pw_hash.rb
@@ -0,0 +1,56 @@
+Puppet::Parser::Functions::newfunction(
+ :pw_hash,
+ :type => :rvalue,
+ :arity => 3,
+ :doc => "Hashes a password using the crypt function. Provides a hash
+ usable on most POSIX systems.
+
+ The first argument to this function is the password to hash. If it is
+ undef or an empty string, this function returns undef.
+
+ The second argument to this function is which type of hash to use. It
+ will be converted into the appropriate crypt(3) hash specifier. Valid
+ hash types are:
+
+ |Hash type |Specifier|
+ |---------------------|---------|
+ |MD5 |1 |
+ |SHA-256 |5 |
+ |SHA-512 (recommended)|6 |
+
+ The third argument to this function is the salt to use.
+
+ Note: this uses the Puppet Master's implementation of crypt(3). If your
+ 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
+ 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',
+ 'sha-256' => '5',
+ 'sha-512' => '6' }
+ hash_type = hashes[args[1].downcase]
+ raise ArgumentError, "pw_hash(): #{args[1]} is not a valid hash type" if hash_type.nil?
+ raise ArgumentError, "pw_hash(): third argument must be a string" unless args[2].is_a? String
+ raise ArgumentError, "pw_hash(): third argument must not be empty" if args[2].empty?
+ raise ArgumentError, "pw_hash(): characters in salt must be in the set [a-zA-Z0-9./]" unless args[2].match(/\A[a-zA-Z0-9.\/]+\z/)
+
+ password = args[0]
+ return nil if password.nil? or password.empty?
+
+ # handle weak implementations of String#crypt
+ if 'test'.crypt('$1$1') != '$1$1$Bp8CU9Oujr9SSEw53WV6G.'
+ # JRuby < 1.7.17
+ if RUBY_PLATFORM == 'java'
+ # override String#crypt for password variable
+ def password.crypt(salt)
+ # puppetserver bundles Apache Commons Codec
+ org.apache.commons.codec.digest.Crypt.crypt(self.to_java_bytes, salt)
+ end
+ else
+ # MS Windows and other systems that don't support enhanced salts
+ raise Puppet::ParseError, 'system does not support enhanced salts'
+ end
+ end
+ password.crypt("$#{hash_type}$#{args[2]}")
+end
diff --git a/lib/puppet/parser/functions/range.rb b/lib/puppet/parser/functions/range.rb
index ffbdf84..49fba21 100644
--- a/lib/puppet/parser/functions/range.rb
+++ b/lib/puppet/parser/functions/range.rb
@@ -65,21 +65,21 @@ Will return: [0,2,4,6,8]
end
end
- # Check whether we have integer value if so then make it so ...
- if start.match(/^\d+$/)
- start = start.to_i
- stop = stop.to_i
- else
- start = start.to_s
- stop = stop.to_s
- end
+ # Check whether we have integer value if so then make it so ...
+ if start.to_s.match(/^\d+$/)
+ start = start.to_i
+ stop = stop.to_i
+ else
+ start = start.to_s
+ stop = stop.to_s
+ end
- range = case type
- when /^(\.\.|\-)$/ then (start .. stop)
- when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
- end
+ range = case type
+ when /^(\.\.|\-)$/ then (start .. stop)
+ when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
+ end
- result = range.step(step).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/reverse.rb b/lib/puppet/parser/functions/reverse.rb
index fe04869..7f1018f 100644
--- a/lib/puppet/parser/functions/reverse.rb
+++ b/lib/puppet/parser/functions/reverse.rb
@@ -12,9 +12,8 @@ Reverses the order of a string or array.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'reverse(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/rstrip.rb b/lib/puppet/parser/functions/rstrip.rb
index 29b0998..0cf8d22 100644
--- a/lib/puppet/parser/functions/rstrip.rb
+++ b/lib/puppet/parser/functions/rstrip.rb
@@ -12,9 +12,8 @@ Strips leading spaces to the right of the string.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'rstrip(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/shuffle.rb b/lib/puppet/parser/functions/shuffle.rb
index 18134ab..30c663d 100644
--- a/lib/puppet/parser/functions/shuffle.rb
+++ b/lib/puppet/parser/functions/shuffle.rb
@@ -12,9 +12,8 @@ Randomizes the order of a string or array elements.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'shuffle(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/strip.rb b/lib/puppet/parser/functions/strip.rb
index 5f4630d..3fac47d 100644
--- a/lib/puppet/parser/functions/strip.rb
+++ b/lib/puppet/parser/functions/strip.rb
@@ -19,9 +19,8 @@ Would result in: "aaa"
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'strip(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/swapcase.rb b/lib/puppet/parser/functions/swapcase.rb
index b9e6632..eb7fe13 100644
--- a/lib/puppet/parser/functions/swapcase.rb
+++ b/lib/puppet/parser/functions/swapcase.rb
@@ -18,9 +18,8 @@ Would result in: "AbCd"
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'swapcase(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/to_bytes.rb b/lib/puppet/parser/functions/to_bytes.rb
index 8ff73d1..df490ea 100644
--- a/lib/puppet/parser/functions/to_bytes.rb
+++ b/lib/puppet/parser/functions/to_bytes.rb
@@ -2,6 +2,8 @@ module Puppet::Parser::Functions
newfunction(:to_bytes, :type => :rvalue, :doc => <<-EOS
Converts the argument into bytes, for example 4 kB becomes 4096.
Takes a single string value as an argument.
+ These conversions reflect a layperson's understanding of
+ 1 MB = 1024 KB, when in fact 1 MB = 1000 KB, and 1 MiB = 1024 KiB.
EOS
) do |arguments|
@@ -21,7 +23,8 @@ module Puppet::Parser::Functions
when 'M' then return (value*(1<<20)).to_i
when 'G' then return (value*(1<<30)).to_i
when 'T' then return (value*(1<<40)).to_i
- when 'E' then return (value*(1<<50)).to_i
+ when 'P' then return (value*(1<<50)).to_i
+ when 'E' then return (value*(1<<60)).to_i
else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
end
end
diff --git a/lib/puppet/parser/functions/type.rb b/lib/puppet/parser/functions/type.rb
index 8d85f11..016529b 100644
--- a/lib/puppet/parser/functions/type.rb
+++ b/lib/puppet/parser/functions/type.rb
@@ -4,46 +4,15 @@
module Puppet::Parser::Functions
newfunction(:type, :type => :rvalue, :doc => <<-EOS
-Returns the type when passed a variable. Type can be one of:
-
-* string
-* array
-* hash
-* float
-* integer
-* boolean
+ DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.
EOS
- ) do |arguments|
-
- raise(Puppet::ParseError, "type(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
-
- value = arguments[0]
-
- klass = value.class
-
- if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
- raise(Puppet::ParseError, 'type(): Unknown type')
- end
-
- klass = klass.to_s # Ugly ...
+ ) do |args|
- # We note that Integer is the parent to Bignum and Fixnum ...
- result = case klass
- when /^(?:Big|Fix)num$/ then 'integer'
- when /^(?:True|False)Class$/ then 'boolean'
- else klass
+ warning("type() DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.")
+ if ! Puppet::Parser::Functions.autoloader.loaded?(:type3x)
+ Puppet::Parser::Functions.autoloader.load(:type3x)
end
-
- if result == "String" then
- if value == value.to_i.to_s then
- result = "Integer"
- elsif value == value.to_f.to_s then
- result = "Float"
- end
- end
-
- return result.downcase
+ function_type3x(args + [false])
end
end
diff --git a/lib/puppet/parser/functions/type3x.rb b/lib/puppet/parser/functions/type3x.rb
new file mode 100644
index 0000000..0800b4a
--- /dev/null
+++ b/lib/puppet/parser/functions/type3x.rb
@@ -0,0 +1,51 @@
+#
+# type3x.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:type3x, :type => :rvalue, :doc => <<-EOS
+DEPRECATED: This function will be removed when puppet 3 support is dropped; please migrate to the new parser's typing system.
+
+Returns the type when passed a value. Type can be one of:
+
+* string
+* array
+* hash
+* float
+* integer
+* boolean
+ EOS
+ ) do |args|
+ raise(Puppet::ParseError, "type3x(): Wrong number of arguments " +
+ "given (#{args.size} for 1)") if args.size < 1
+
+ value = args[0]
+
+ klass = value.class
+
+ if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
+ raise(Puppet::ParseError, 'type3x(): Unknown type')
+ end
+
+ klass = klass.to_s # Ugly ...
+
+ # We note that Integer is the parent to Bignum and Fixnum ...
+ result = case klass
+ when /^(?:Big|Fix)num$/ then 'integer'
+ when /^(?:True|False)Class$/ then 'boolean'
+ else klass
+ end
+
+ if result == "String" then
+ if value == value.to_i.to_s then
+ result = "Integer"
+ elsif value == value.to_f.to_s then
+ result = "Float"
+ end
+ end
+
+ return result.downcase
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/unique.rb b/lib/puppet/parser/functions/unique.rb
index 8844a74..cf770f3 100644
--- a/lib/puppet/parser/functions/unique.rb
+++ b/lib/puppet/parser/functions/unique.rb
@@ -28,9 +28,8 @@ This returns:
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'unique(): Requires either ' +
'array or string to work with')
end
diff --git a/lib/puppet/parser/functions/upcase.rb b/lib/puppet/parser/functions/upcase.rb
index fe6cadc..0226a88 100644
--- a/lib/puppet/parser/functions/upcase.rb
+++ b/lib/puppet/parser/functions/upcase.rb
@@ -13,23 +13,27 @@ Converts a string or an array of strings to uppercase.
Will return:
ASDF
- EOS
+ EOS
) do |arguments|
raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
+ "given (#{arguments.size} for 1)") if arguments.size != 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
- raise(Puppet::ParseError, 'upcase(): Requires either ' +
- 'array or string to work with')
+ unless value.is_a?(Array) || value.is_a?(Hash) || value.respond_to?(:upcase)
+ raise(Puppet::ParseError, 'upcase(): Requires an ' +
+ 'array, hash or object that responds to upcase in order to work')
end
if value.is_a?(Array)
# Numbers in Puppet are often string-encoded which is troublesome ...
- result = value.collect { |i| i.is_a?(String) ? i.upcase : i }
+ result = value.collect { |i| function_upcase([i]) }
+ elsif value.is_a?(Hash)
+ result = {}
+ value.each_pair do |k, v|
+ result[function_upcase([k])] = function_upcase([v])
+ end
else
result = value.upcase
end
diff --git a/lib/puppet/parser/functions/uriescape.rb b/lib/puppet/parser/functions/uriescape.rb
index 0d81de5..45bbed2 100644
--- a/lib/puppet/parser/functions/uriescape.rb
+++ b/lib/puppet/parser/functions/uriescape.rb
@@ -14,16 +14,15 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
- klass = value.class
- unless [Array, String].include?(klass)
+ unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'uriescape(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
# Numbers in Puppet are often string-encoded which is troublesome ...
- result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i }
+ result = value.collect { |i| i.is_a?(String) ? URI.escape(i) : i }
else
result = URI.escape(value)
end
diff --git a/lib/puppet/parser/functions/validate_absolute_path.rb b/lib/puppet/parser/functions/validate_absolute_path.rb
index fe27974..b696680 100644
--- a/lib/puppet/parser/functions/validate_absolute_path.rb
+++ b/lib/puppet/parser/functions/validate_absolute_path.rb
@@ -5,15 +5,20 @@ module Puppet::Parser::Functions
The following values will pass:
- $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
+ $my_path = 'C:/Program Files (x86)/Puppet Labs/Puppet'
validate_absolute_path($my_path)
- $my_path2 = "/var/lib/puppet"
+ $my_path2 = '/var/lib/puppet'
validate_absolute_path($my_path2)
-
+ $my_path3 = ['C:/Program Files (x86)/Puppet Labs/Puppet','C:/Program Files/Puppet Labs/Puppet']
+ validate_absolute_path($my_path3)
+ $my_path4 = ['/var/lib/puppet','/usr/share/puppet']
+ validate_absolute_path($my_path4)
The following values will fail, causing compilation to abort:
validate_absolute_path(true)
+ validate_absolute_path('../var/lib/puppet')
+ validate_absolute_path('var/lib/puppet')
validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
$undefined = undef
@@ -28,28 +33,36 @@ module Puppet::Parser::Functions
end
args.each do |arg|
- # This logic was borrowed from
- # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
-
- # Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
- if Puppet::Util.respond_to?(:absolute_path?) then
- unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows)
- raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
+ # put arg to candidate var to be able to replace it
+ candidates = arg
+ # if arg is just a string with a path to test, convert it to an array
+ # to avoid test code duplication
+ unless arg.is_a?(Array) then
+ candidates = Array.new(1,arg)
+ end
+ # iterate over all pathes within the candidates array
+ candidates.each do |path|
+ # This logic was borrowed from
+ # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
+ # Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
+ if Puppet::Util.respond_to?(:absolute_path?) then
+ unless Puppet::Util.absolute_path?(path, :posix) or Puppet::Util.absolute_path?(path, :windows)
+ raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
+ end
+ else
+ # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
+ # Determine in a platform-specific way whether a path is absolute. This
+ # defaults to the local platform if none is specified.
+ # Escape once for the string literal, and once for the regex.
+ slash = '[\\\\/]'
+ name = '[^\\\\/]+'
+ regexes = {
+ :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
+ :posix => %r!^/!,
+ }
+ rval = (!!(path =~ regexes[:posix])) || (!!(path =~ regexes[:windows]))
+ rval or raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
end
- else
- # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
- # Determine in a platform-specific way whether a path is absolute. This
- # defaults to the local platform if none is specified.
- # Escape once for the string literal, and once for the regex.
- slash = '[\\\\/]'
- name = '[^\\\\/]+'
- regexes = {
- :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
- :posix => %r!^/!,
- }
-
- rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows]))
- rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
end
end
end
diff --git a/lib/puppet/parser/functions/validate_augeas.rb b/lib/puppet/parser/functions/validate_augeas.rb
index 154d660..4ea4fe0 100644
--- a/lib/puppet/parser/functions/validate_augeas.rb
+++ b/lib/puppet/parser/functions/validate_augeas.rb
@@ -1,3 +1,5 @@
+require 'tempfile'
+
module Puppet::Parser::Functions
newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
Perform validation of a string using an Augeas lens
diff --git a/lib/puppet/parser/functions/validate_cmd.rb b/lib/puppet/parser/functions/validate_cmd.rb
index 2ebe91c..5df3c60 100644
--- a/lib/puppet/parser/functions/validate_cmd.rb
+++ b/lib/puppet/parser/functions/validate_cmd.rb
@@ -1,13 +1,14 @@
require 'puppet/util/execution'
+require 'tempfile'
module Puppet::Parser::Functions
newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args|
Perform validation of a string with an external command.
The first argument of this function should be a string to
test, and the second argument should be a path to a test command
- taking a file as last argument. If the command, launched against
- a tempfile containing the passed string, returns a non-null value,
- compilation will abort with a parse error.
+ taking a % as a placeholder for the file path (will default to the end).
+ If the command, launched against a tempfile containing the passed string,
+ returns a non-null value, compilation will abort with a parse error.
If a third argument is specified, this will be the error message raised and
seen by the user.
@@ -16,8 +17,12 @@ module Puppet::Parser::Functions
Example:
+ # Defaults to end of path
validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
+ # % as file location
+ validate_cmd($haproxycontent, '/usr/sbin/haproxy -f % -c', 'Haproxy failed to validate config content')
+
ENDHEREDOC
if (args.length < 2) or (args.length > 3) then
raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)")
@@ -33,14 +38,24 @@ module Puppet::Parser::Functions
begin
tmpfile.write(content)
tmpfile.close
+
+ if checkscript =~ /\s%(\s|$)/
+ check_with_correct_location = checkscript.gsub(/%/,tmpfile.path)
+ else
+ check_with_correct_location = "#{checkscript} #{tmpfile.path}"
+ end
+
if Puppet::Util::Execution.respond_to?('execute')
- Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}")
+ Puppet::Util::Execution.execute(check_with_correct_location)
else
- Puppet::Util.execute("#{checkscript} #{tmpfile.path}")
+ Puppet::Util.execute(check_with_correct_location)
end
rescue Puppet::ExecutionFailure => detail
msg += "\n#{detail}"
raise Puppet::ParseError, msg
+ rescue Exception => detail
+ msg += "\n#{detail.class.name} #{detail}"
+ raise Puppet::ParseError, msg
ensure
tmpfile.unlink
end
diff --git a/lib/puppet/parser/functions/validate_integer.rb b/lib/puppet/parser/functions/validate_integer.rb
new file mode 100644
index 0000000..995f8db
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_integer.rb
@@ -0,0 +1,131 @@
+module Puppet::Parser::Functions
+
+ newfunction(:validate_integer, :doc => <<-'ENDHEREDOC') do |args|
+ Validate that the first argument is an integer (or an array of integers). Abort catalog compilation if any of the checks fail.
+
+ The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max.
+
+ The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min.
+ If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check
+ if (all elements of) the first argument are greater or equal to the given minimum.
+
+ It will fail if the first argument is not an integer or array of integers, and if arg 2 and arg 3 are not convertable to an integer.
+
+ The following values will pass:
+
+ validate_integer(1)
+ validate_integer(1, 2)
+ validate_integer(1, 1)
+ validate_integer(1, 2, 0)
+ validate_integer(2, 2, 2)
+ validate_integer(2, '', 0)
+ validate_integer(2, undef, 0)
+ $foo = undef
+ validate_integer(2, $foo, 0)
+ validate_integer([1,2,3,4,5], 6)
+ validate_integer([1,2,3,4,5], 6, 0)
+
+ Plus all of the above, but any combination of values passed as strings ('1' or "1").
+ Plus all of the above, but with (correct) combinations of negative integer values.
+
+ The following values will not:
+
+ validate_integer(true)
+ validate_integer(false)
+ validate_integer(7.0)
+ validate_integer({ 1 => 2 })
+ $foo = undef
+ validate_integer($foo)
+ validate_integer($foobaridontexist)
+
+ validate_integer(1, 0)
+ validate_integer(1, true)
+ validate_integer(1, '')
+ validate_integer(1, undef)
+ validate_integer(1, , 0)
+ validate_integer(1, 2, 3)
+ validate_integer(1, 3, 2)
+ validate_integer(1, 3, true)
+
+ Plus all of the above, but any combination of values passed as strings ('false' or "false").
+ Plus all of the above, but with incorrect combinations of negative integer values.
+ Plus all of the above, but with non-integer crap in arrays or maximum / minimum argument.
+
+ ENDHEREDOC
+
+ # tell the user we need at least one, and optionally up to two other parameters
+ raise Puppet::ParseError, "validate_integer(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4
+
+ input, max, min = *args
+
+ # check maximum parameter
+ if args.length > 1
+ max = max.to_s
+ # allow max to be empty (or undefined) if we have a minimum set
+ if args.length > 2 and max == ''
+ max = nil
+ else
+ begin
+ max = Integer(max)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_integer(): Expected second argument to be unset or an Integer, got #{max}:#{max.class}"
+ end
+ end
+ else
+ max = nil
+ end
+
+ # check minimum parameter
+ if args.length > 2
+ begin
+ min = Integer(min.to_s)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_integer(): Expected third argument to be unset or an Integer, got #{min}:#{min.class}"
+ end
+ else
+ min = nil
+ end
+
+ # ensure that min < max
+ if min and max and min > max
+ raise Puppet::ParseError, "validate_integer(): Expected second argument to be larger than third argument, got #{max} < #{min}"
+ end
+
+ # create lamba validator function
+ validator = lambda do |num|
+ # check input < max
+ if max and num > max
+ raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}."
+ end
+ # check input > min (this will only be checked if no exception has been raised before)
+ if min and num < min
+ raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}."
+ end
+ end
+
+ # if this is an array, handle it.
+ case input
+ when Array
+ # check every element of the array
+ input.each_with_index do |arg, pos|
+ begin
+ arg = Integer(arg.to_s)
+ validator.call(arg)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_integer(): Expected element at array position #{pos} to be an Integer, got #{arg.class}"
+ end
+ end
+ # for the sake of compatibility with ruby 1.8, we need extra handling of hashes
+ when Hash
+ raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}"
+ # check the input. this will also fail any stuff other than pure, shiny integers
+ else
+ begin
+ input = Integer(input.to_s)
+ validator.call(input)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}"
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_numeric.rb b/lib/puppet/parser/functions/validate_numeric.rb
new file mode 100644
index 0000000..d2e4d16
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_numeric.rb
@@ -0,0 +1,93 @@
+module Puppet::Parser::Functions
+
+ newfunction(:validate_numeric, :doc => <<-'ENDHEREDOC') do |args|
+ Validate that the first argument is a numeric value (or an array of numeric values). Abort catalog compilation if any of the checks fail.
+
+ The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max.
+
+ The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min.
+ If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check
+ if (all elements of) the first argument are greater or equal to the given minimum.
+
+ It will fail if the first argument is not a numeric (Integer or Float) or array of numerics, and if arg 2 and arg 3 are not convertable to a numeric.
+
+ For passing and failing usage, see `validate_integer()`. It is all the same for validate_numeric, yet now floating point values are allowed, too.
+
+ ENDHEREDOC
+
+ # tell the user we need at least one, and optionally up to two other parameters
+ raise Puppet::ParseError, "validate_numeric(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4
+
+ input, max, min = *args
+
+ # check maximum parameter
+ if args.length > 1
+ max = max.to_s
+ # allow max to be empty (or undefined) if we have a minimum set
+ if args.length > 2 and max == ''
+ max = nil
+ else
+ begin
+ max = Float(max)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_numeric(): Expected second argument to be unset or a Numeric, got #{max}:#{max.class}"
+ end
+ end
+ else
+ max = nil
+ end
+
+ # check minimum parameter
+ if args.length > 2
+ begin
+ min = Float(min.to_s)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_numeric(): Expected third argument to be unset or a Numeric, got #{min}:#{min.class}"
+ end
+ else
+ min = nil
+ end
+
+ # ensure that min < max
+ if min and max and min > max
+ raise Puppet::ParseError, "validate_numeric(): Expected second argument to be larger than third argument, got #{max} < #{min}"
+ end
+
+ # create lamba validator function
+ validator = lambda do |num|
+ # check input < max
+ if max and num > max
+ raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}."
+ end
+ # check input > min (this will only be checked if no exception has been raised before)
+ if min and num < min
+ raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}."
+ end
+ end
+
+ # if this is an array, handle it.
+ case input
+ when Array
+ # check every element of the array
+ input.each_with_index do |arg, pos|
+ begin
+ arg = Float(arg.to_s)
+ validator.call(arg)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_numeric(): Expected element at array position #{pos} to be a Numeric, got #{arg.class}"
+ end
+ end
+ # for the sake of compatibility with ruby 1.8, we need extra handling of hashes
+ when Hash
+ raise Puppet::ParseError, "validate_integer(): Expected first argument to be a Numeric or Array, got #{input.class}"
+ # check the input. this will also fail any stuff other than pure, shiny integers
+ else
+ begin
+ input = Float(input.to_s)
+ validator.call(input)
+ rescue TypeError, ArgumentError
+ raise Puppet::ParseError, "validate_numeric(): Expected first argument to be a Numeric or Array, got #{input.class}"
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_string.rb b/lib/puppet/parser/functions/validate_string.rb
index e667794..c841f6a 100644
--- a/lib/puppet/parser/functions/validate_string.rb
+++ b/lib/puppet/parser/functions/validate_string.rb
@@ -13,9 +13,14 @@ module Puppet::Parser::Functions
validate_string(true)
validate_string([ 'some', 'array' ])
- $undefined = undef
- validate_string($undefined)
-
+
+ Note: validate_string(undef) will not fail in this version of the
+ functions API (incl. current and future parser). Instead, use:
+
+ if $var == undef {
+ fail('...')
+ }
+
ENDHEREDOC
unless args.length > 0 then
diff --git a/lib/puppet/parser/functions/values_at.rb b/lib/puppet/parser/functions/values_at.rb
index d3e69d9..f350f53 100644
--- a/lib/puppet/parser/functions/values_at.rb
+++ b/lib/puppet/parser/functions/values_at.rb
@@ -49,6 +49,7 @@ Would return ['a','c','d'].
indices_list = []
indices.each do |i|
+ i = i.to_s
if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
start = m[1].to_i
stop = m[3].to_i
diff --git a/lib/puppet/parser/functions/zip.rb b/lib/puppet/parser/functions/zip.rb
index 2b56e9c..3074f28 100644
--- a/lib/puppet/parser/functions/zip.rb
+++ b/lib/puppet/parser/functions/zip.rb
@@ -27,33 +27,7 @@ Would result in:
raise(Puppet::ParseError, 'zip(): Requires array to work with')
end
- flatten = arguments[2] if arguments[2]
-
- if flatten
- klass = flatten.class
-
- # We can have either true or false, or string which resembles boolean ...
- unless [FalseClass, TrueClass, String].include?(klass)
- raise(Puppet::ParseError, 'zip(): Requires either ' +
- 'boolean or string to work with')
- end
-
- if flatten.is_a?(String)
- # We consider all the yes, no, y, n and so on too ...
- flatten = case flatten
- #
- # This is how undef looks like in Puppet ...
- # We yield false in this case.
- #
- when /^$/, '' then false # Empty string will be false ...
- when /^(1|t|y|true|yes)$/ then true
- when /^(0|f|n|false|no)$/ then false
- when /^(undef|undefined)$/ then false # This is not likely to happen ...
- else
- raise(Puppet::ParseError, 'zip(): Unknown type of boolean given')
- end
- end
- end
+ flatten = function_str2bool([arguments[2]]) if arguments[2]
result = a.zip(b)
result = flatten ? result.flatten : result
diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb
index 94e7fac..e7854f0 100644
--- a/lib/puppet/provider/file_line/ruby.rb
+++ b/lib/puppet/provider/file_line/ruby.rb
@@ -34,13 +34,22 @@ 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
+ regex_after = resource[:after] ? Regexp.new(resource[:after]) : nil
+ match_count = count_matches(regex)
+
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|
fh.puts(regex.match(l) ? resource[:line] : l)
+ if (match_count == 0 and regex_after)
+ if regex_after.match(l)
+ fh.puts(resource[:line])
+ match_count += 1 #Increment match_count to indicate that the new line has been inserted.
+ end
+ end
end
if (match_count == 0)
@@ -51,9 +60,7 @@ Puppet::Type.type(:file_line).provide(:ruby) do
def handle_create_with_after
regex = Regexp.new(resource[:after])
-
- count = lines.count {|l| l.match(regex)}
-
+ count = count_matches(regex)
case count
when 1 # find the line to put our line after
File.open(resource[:path], 'w') do |fh|
@@ -71,12 +78,19 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end
end
+ def count_matches(regex)
+ lines.select{|l| l.match(regex)}.size
+ end
+
##
# append the line to the file.
#
# @api private
def append_line
- File.open(resource[:path], 'a') do |fh|
+ File.open(resource[:path], 'w') do |fh|
+ lines.each do |l|
+ fh.puts(l)
+ end
fh.puts resource[:line]
end
end
diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb
index 9dbe43c..29f9538 100644
--- a/lib/puppet/type/file_line.rb
+++ b/lib/puppet/type/file_line.rb
@@ -3,9 +3,9 @@ Puppet::Type.newtype(:file_line) do
desc <<-EOT
Ensures that a given line is contained within a file. The implementation
matches the full line, including whitespace at the beginning and end. If
- the line is not contained in the given file, Puppet will add the line to
- ensure the desired state. Multiple resources may be declared to manage
- multiple lines in the same file.
+ the line is not contained in the given file, Puppet will append the line to
+ the end of the file to ensure the desired state. Multiple resources may
+ be declared to manage multiple lines in the same file.
Example:
@@ -13,6 +13,7 @@ Puppet::Type.newtype(:file_line) do
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
+
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
@@ -21,6 +22,18 @@ Puppet::Type.newtype(:file_line) do
In this example, Puppet will ensure both of the specified lines are
contained in the file /etc/sudoers.
+ Match Example:
+
+ file_line { 'bashrc_proxy':
+ ensure => present,
+ path => '/etc/bashrc',
+ line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128',
+ match => '^export\ HTTP_PROXY\=',
+ }
+
+ In this code example match will look for a line beginning with export
+ followed by HTTP_PROXY and replace it with the value in line.
+
**Autorequires:** If Puppet is managing the file that will contain the line
being managed, the file_line resource will autorequire that file.
@@ -36,12 +49,15 @@ Puppet::Type.newtype(:file_line) do
end
newparam(:match) do
- desc 'An optional regular expression to run against existing lines in the file;\n' +
- 'if a match is found, we replace that line rather than adding a new line.'
+ desc 'An optional ruby regular expression to run against existing lines in the file.' +
+ ' If a match is found, we replace that line rather than adding a new line.' +
+ ' A regex comparisson is performed against the line value and if it does not' +
+ ' match an exception will be raised. '
end
newparam(:multiple) do
- desc 'An optional value to determine if match can change multiple lines.'
+ desc 'An optional value to determine if match can change multiple lines.' +
+ ' If set to false, an exception will be raised if more than one line matches'
newvalues(true, false)
end
@@ -50,7 +66,7 @@ Puppet::Type.newtype(:file_line) do
end
newparam(:line) do
- desc 'The line to be appended to the file located by the path parameter.'
+ desc 'The line to be appended to the file or used to replace matches found by the match attribute.'
end
newparam(:path) do
@@ -71,12 +87,5 @@ Puppet::Type.newtype(:file_line) do
unless self[:line] and self[:path]
raise(Puppet::Error, "Both line and path are required attributes")
end
-
- if (self[:match])
- unless Regexp.new(self[:match]).match(self[:line])
- raise(Puppet::Error, "When providing a 'match' parameter, the value must be a regex that matches against the value of your 'line' parameter")
- end
- end
-
end
end