Added modules

This commit is contained in:
Ciaby 2014-07-11 13:30:23 -05:00
parent c53c931217
commit 59ec520742
646 changed files with 35182 additions and 0 deletions

View file

@ -0,0 +1,36 @@
#
# abs.rb
#
module Puppet::Parser::Functions
newfunction(:abs, :type => :rvalue, :doc => <<-EOS
Returns the absolute value of a number, for example -34.56 becomes
34.56. Takes a single integer and float value as an argument.
EOS
) do |arguments|
raise(Puppet::ParseError, "abs(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
# Numbers in Puppet are often string-encoded which is troublesome ...
if value.is_a?(String)
if value.match(/^-?(?:\d+)(?:\.\d+){1}$/)
value = value.to_f
elsif value.match(/^-?\d+$/)
value = value.to_i
else
raise(Puppet::ParseError, 'abs(): Requires float or ' +
'integer to work with')
end
end
# We have numeric value to handle ...
result = value.abs
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,33 @@
#
# any2array.rb
#
module Puppet::Parser::Functions
newfunction(:any2array, :type => :rvalue, :doc => <<-EOS
This converts any object to an array containing that object. Empty argument
lists are converted to an empty array. Arrays are left untouched. Hashes are
converted to arrays of alternating keys and values.
EOS
) do |arguments|
if arguments.empty?
return []
end
if arguments.length == 1
if arguments[0].kind_of?(Array)
return arguments[0]
elsif arguments[0].kind_of?(Hash)
result = []
arguments[0].each do |key, value|
result << key << value
end
return result
end
end
return arguments
end
end
# vim: set ts=2 sw=2 et :

View file

@ -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

View file

@ -0,0 +1,49 @@
#
# bool2num.rb
#
module Puppet::Parser::Functions
newfunction(:bool2num, :type => :rvalue, :doc => <<-EOS
Converts a boolean to a number. Converts the values:
false, f, 0, n, and no to 0
true, t, 1, y, and yes to 1
Requires a single boolean or string as an input.
EOS
) do |arguments|
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
# We have real boolean values as well ...
result = value ? 1 : 0
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,34 @@
#
# capitalize.rb
#
module Puppet::Parser::Functions
newfunction(:capitalize, :type => :rvalue, :doc => <<-EOS
Capitalizes the first letter of a string or array of strings.
Requires either a single string or an array as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "capitalize(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'capitalize(): 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) ? i.capitalize : i }
else
result = value.capitalize
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,35 @@
#
# chomp.rb
#
module Puppet::Parser::Functions
newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
Removes the record separator from the end of a string or an array of
strings, for example `hello\n` becomes `hello`.
Requires a single string or array as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "chomp(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'chomp(): 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) ? i.chomp : i }
else
result = value.chomp
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,37 @@
#
# chop.rb
#
module Puppet::Parser::Functions
newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
Returns a new string with the last character removed. If the string ends
with `\r\n`, both characters are removed. Applying chop to an empty
string returns an empty string. If you wish to merely remove record
separators then you should use the `chomp` function.
Requires a string or array of strings as input.
EOS
) do |arguments|
raise(Puppet::ParseError, "chop(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'chop(): Requires either an ' +
'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) ? i.chop : i }
else
result = value.chop
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,41 @@
#
# concat.rb
#
module Puppet::Parser::Functions
newfunction(:concat, :type => :rvalue, :doc => <<-EOS
Appends the contents of array 2 onto array 1.
*Example:*
concat(['1','2','3'],['4','5','6'])
Would result in:
['1','2','3','4','5','6']
EOS
) do |arguments|
# Check that 2 arguments have been given ...
raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
"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
if b.is_a?(Array)
result = a.concat(b)
else
result = a << b
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,22 @@
module Puppet::Parser::Functions
newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS
Takes an array as first argument and an optional second argument.
Count the number of elements in array that matches second argument.
If called with only an array it counts the number of elements that are not nil/undef.
EOS
) do |args|
if (args.size > 2) then
raise(ArgumentError, "count(): Wrong number of arguments "+
"given #{args.size} for 1 or 2.")
end
collection, item = args
if item then
collection.count item
else
collection.count { |obj| obj != nil && obj != :undef && obj != '' }
end
end
end

View file

@ -0,0 +1,44 @@
module Puppet::Parser::Functions
newfunction(:deep_merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Recursively merges two or more hashes together and returns the resulting hash.
For example:
$hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
$hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } }
$merged_hash = deep_merge($hash1, $hash2)
# The resulting hash is equivalent to:
# $merged_hash = { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } }
When there is a duplicate key that is a hash, they are recursively merged.
When there is a duplicate key that is not a hash, the key in the rightmost hash will "win."
ENDHEREDOC
if args.length < 2
raise Puppet::ParseError, ("deep_merge(): wrong number of arguments (#{args.length}; must be at least 2)")
end
deep_merge = Proc.new do |hash1,hash2|
hash1.merge(hash2) do |key,old_value,new_value|
if old_value.is_a?(Hash) && new_value.is_a?(Hash)
deep_merge.call(old_value, new_value)
else
new_value
end
end
end
result = Hash.new
args.each do |arg|
next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
# If the argument was not a hash, skip it.
unless arg.is_a?(Hash)
raise Puppet::ParseError, "deep_merge: unexpected argument type #{arg.class}, only expects hash arguments"
end
result = deep_merge.call(result, arg)
end
return( result )
end
end

View file

@ -0,0 +1,35 @@
# Test whether a given class or definition is defined
require 'puppet/parser/functions'
Puppet::Parser::Functions.newfunction(:defined_with_params,
:type => :rvalue,
:doc => <<-'ENDOFDOC'
Takes a resource reference and an optional hash of attributes.
Returns true if a resource with the specified attributes has already been added
to the catalog, and false otherwise.
user { 'dan':
ensure => present,
}
if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
user { 'dan': ensure => present, }
}
ENDOFDOC
) do |vals|
reference, params = vals
raise(ArgumentError, 'Must specify a reference') unless reference
if (! params) || params == ''
params = {}
end
ret = false
if resource = findresource(reference.to_s)
matches = params.collect do |key, value|
resource[key] == value
end
ret = params.empty? || !matches.include?(false)
end
Puppet.debug("Resource #{reference} was not determined to be defined")
ret
end

View file

@ -0,0 +1,46 @@
#
# delete.rb
#
# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
module Puppet::Parser::Functions
newfunction(:delete, :type => :rvalue, :doc => <<-EOS
Deletes all instances of a given element from an array, substring from a
string, or key from a hash.
*Examples:*
delete(['a','b','c','b'], 'b')
Would return: ['a','c']
delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
Would return: {'a'=>1,'c'=>3}
delete('abracadabra', 'bra')
Would return: 'acada'
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
"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}.")
end
collection
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,49 @@
#
# delete_at.rb
#
module Puppet::Parser::Functions
newfunction(:delete_at, :type => :rvalue, :doc => <<-EOS
Deletes a determined indexed value from an array.
*Examples:*
delete_at(['a','b','c'], 1)
Would return: ['a','c']
EOS
) do |arguments|
raise(Puppet::ParseError, "delete_at(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'delete_at(): Requires array to work with')
end
index = arguments[1]
if index.is_a?(String) and not index.match(/^\d+$/)
raise(Puppet::ParseError, 'delete_at(): You must provide ' +
'non-negative numeric index')
end
result = array.clone
# Numbers in Puppet are often string-encoded which is troublesome ...
index = index.to_i
if index > result.size - 1 # First element is at index 0 is it not?
raise(Puppet::ParseError, 'delete_at(): Given index ' +
'exceeds size of array given')
end
result.delete_at(index) # We ignore the element that got deleted ...
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -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
unless args[0].is_a? Array or args[0].is_a? Hash
raise(Puppet::ParseError,
"delete_undef_values(): expected an array or hash, got #{args[0]} type #{args[0].class} ")
end
result = args[0].dup
if result.is_a?(Hash)
result.delete_if {|key, val| val.equal? :undef}
elsif result.is_a?(Array)
result.delete :undef
end
result
end
end

View file

@ -0,0 +1,26 @@
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, item = arguments
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.dup.delete_if { |key, val| item == val }
end
end

View file

@ -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 :

View file

@ -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 :

View file

@ -0,0 +1,33 @@
#
# downcase.rb
#
module Puppet::Parser::Functions
newfunction(:downcase, :type => :rvalue, :doc => <<-EOS
Converts the case of a string or all strings in an array to lower case.
EOS
) do |arguments|
raise(Puppet::ParseError, "downcase(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'downcase(): 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) ? i.downcase : i }
else
result = value.downcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,28 @@
#
# empty.rb
#
module Puppet::Parser::Functions
newfunction(:empty, :type => :rvalue, :doc => <<-EOS
Returns true if the variable is empty.
EOS
) do |arguments|
raise(Puppet::ParseError, "empty(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, Hash, String].include?(klass)
raise(Puppet::ParseError, 'empty(): Requires either ' +
'array, hash or string to work with')
end
result = value.empty?
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,35 @@
#
# ensure_packages.rb
#
module Puppet::Parser::Functions
newfunction(:ensure_packages, :type => :statement, :doc => <<-EOS
Takes a list of packages and only installs them if they don't already exist.
It optionally takes a hash as a second parameter that will be passed as the
third argument to the ensure_resource() function.
EOS
) do |arguments|
if arguments.size > 2 or arguments.size == 0
raise(Puppet::ParseError, "ensure_packages(): Wrong number of arguments " +
"given (#{arguments.size} for 1 or 2)")
elsif arguments.size == 2 and !arguments[1].is_a?(Hash)
raise(Puppet::ParseError, 'ensure_packages(): Requires second argument to be a Hash')
end
packages = Array(arguments[0])
if arguments[1]
defaults = { 'ensure' => 'present' }.merge(arguments[1])
else
defaults = { 'ensure' => 'present' }
end
Puppet::Parser::Functions.function(:ensure_resource)
packages.each { |package_name|
function_ensure_resource(['package', package_name, defaults ])
}
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,45 @@
# Test whether a given class or definition is defined
require 'puppet/parser/functions'
Puppet::Parser::Functions.newfunction(:ensure_resource,
:type => :statement,
:doc => <<-'ENDOFDOC'
Takes a resource type, title, and a list of attributes that describe a
resource.
user { 'dan':
ensure => present,
}
This example only creates the resource if it does not already exist:
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 ||= {}
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

View file

@ -0,0 +1,33 @@
#
# flatten.rb
#
module Puppet::Parser::Functions
newfunction(:flatten, :type => :rvalue, :doc => <<-EOS
This function flattens any deeply nested arrays and returns a single flat array
as a result.
*Examples:*
flatten(['a', ['b', ['c']]])
Would return: ['a','b','c']
EOS
) do |arguments|
raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'flatten(): Requires array to work with')
end
result = array.flatten
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,25 @@
module Puppet::Parser::Functions
newfunction(:floor, :type => :rvalue, :doc => <<-EOS
Returns the largest integer less or equal to the argument.
Takes a single numeric value as an argument.
EOS
) do |arguments|
raise(Puppet::ParseError, "floor(): 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, "floor(): Wrong argument type " +
"given (#{arguments[0]} for Numeric)")
end
raise(Puppet::ParseError, "floor(): Wrong argument type " +
"given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false
arg.floor
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,46 @@
#
# fqdn_rotate.rb
#
module Puppet::Parser::Functions
newfunction(:fqdn_rotate, :type => :rvalue, :doc => <<-EOS
Rotates an array a random number of times based on a nodes fqdn.
EOS
) do |arguments|
raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
require 'digest/md5'
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# Check whether it makes sense to rotate ...
return result if result.size <= 1
# We turn any string value into an array to be able to rotate ...
result = string ? result.split('') : result
elements = result.size
srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
rand(elements).times {
result.push result.shift
}
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,17 @@
module Puppet::Parser::Functions
newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
Returns the absolute path of the specified module for the current
environment.
Example:
$module_path = get_module_path('stdlib')
EOT
) do |args|
raise(Puppet::ParseError, "get_module_path(): Wrong number of arguments, expects one") unless args.size == 1
if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
module_path.path
else
raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
end
end
end

View file

@ -0,0 +1,35 @@
# Test whether a given class or definition is defined
require 'puppet/parser/functions'
Puppet::Parser::Functions.newfunction(:getparam,
:type => :rvalue,
:doc => <<-'ENDOFDOC'
Takes a resource reference and name of the parameter and
returns value of resource's parameter.
*Examples:*
define example_resource($param) {
}
example_resource { "example_resource_instance":
param => "param_value"
}
getparam(Example_resource["example_resource_instance"], "param")
Would return: param_value
ENDOFDOC
) do |vals|
reference, param = vals
raise(ArgumentError, 'Must specify a reference') unless reference
raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String
return '' if param.empty?
if resource = findresource(reference.to_s)
return resource[param] if resource[param]
end
return ''
end

View file

@ -0,0 +1,26 @@
module Puppet::Parser::Functions
newfunction(:getvar, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Lookup a variable in a remote namespace.
For example:
$foo = getvar('site::data::foo')
# Equivalent to $foo = $site::data::foo
This is useful if the namespace itself is stored in a string:
$datalocation = 'site::data'
$bar = getvar("${datalocation}::bar")
# Equivalent to $bar = $site::data::bar
ENDHEREDOC
unless args.length == 1
raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
end
self.lookupvar("#{args[0]}")
end
end

View file

@ -0,0 +1,33 @@
#
# grep.rb
#
module Puppet::Parser::Functions
newfunction(:grep, :type => :rvalue, :doc => <<-EOS
This function searches through an array and returns any elements that match
the provided regular expression.
*Examples:*
grep(['aaa','bbb','ccc','aaaddd'], 'aaa')
Would return:
['aaa','aaaddd']
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "grep(): Wrong number of arguments "+
"given #{arguments.size} for 2")
end
a = arguments[0]
pattern = Regexp.new(arguments[1])
a.grep(pattern)
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,52 @@
#
# has_interface_with
#
module Puppet::Parser::Functions
newfunction(:has_interface_with, :type => :rvalue, :doc => <<-EOS
Returns boolean based on kind and value:
* macaddress
* netmask
* ipaddress
* network
has_interface_with("macaddress", "x:x:x:x:x:x")
has_interface_with("ipaddress", "127.0.0.1") => true
etc.
If no "kind" is given, then the presence of the interface is checked:
has_interface_with("lo") => true
EOS
) do |args|
raise(Puppet::ParseError, "has_interface_with(): Wrong number of arguments " +
"given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
interfaces = lookupvar('interfaces')
# If we do not have any interfaces, then there are no requested attributes
return false if (interfaces == :undefined)
interfaces = interfaces.split(',')
if args.size == 1
return interfaces.member?(args[0])
end
kind, value = args
if lookupvar(kind) == value
return true
end
result = false
interfaces.each do |iface|
if value == lookupvar("#{kind}_#{iface}")
result = true
break
end
end
result
end
end

View file

@ -0,0 +1,25 @@
#
# has_ip_address
#
module Puppet::Parser::Functions
newfunction(:has_ip_address, :type => :rvalue, :doc => <<-EOS
Returns true if the client has the requested IP address on some interface.
This function iterates through the 'interfaces' fact and checks the
'ipaddress_IFACE' facts, performing a simple string comparison.
EOS
) do |args|
raise(Puppet::ParseError, "has_ip_address(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size != 1
Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
function_has_interface_with(['ipaddress', args[0]])
end
end
# vim:sts=2 sw=2

View file

@ -0,0 +1,25 @@
#
# has_ip_network
#
module Puppet::Parser::Functions
newfunction(:has_ip_network, :type => :rvalue, :doc => <<-EOS
Returns true if the client has an IP address within the requested network.
This function iterates through the 'interfaces' fact and checks the
'network_IFACE' facts, performing a simple string comparision.
EOS
) do |args|
raise(Puppet::ParseError, "has_ip_network(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size != 1
Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
function_has_interface_with(['network', args[0]])
end
end
# vim:sts=2 sw=2

View file

@ -0,0 +1,28 @@
module Puppet::Parser::Functions
newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Determine if a hash has a certain key value.
Example:
$my_hash = {'key_one' => 'value_one'}
if has_key($my_hash, 'key_two') {
notice('we will not reach here')
}
if has_key($my_hash, 'key_one') {
notice('this will be printed')
}
ENDHEREDOC
unless args.length == 2
raise Puppet::ParseError, ("has_key(): wrong number of arguments (#{args.length}; must be 2)")
end
unless args[0].is_a?(Hash)
raise Puppet::ParseError, "has_key(): expects the first argument to be a hash, got #{args[0].inspect} which is of type #{args[0].class}"
end
args[0].has_key?(args[1])
end
end

View file

@ -0,0 +1,41 @@
#
# hash.rb
#
module Puppet::Parser::Functions
newfunction(:hash, :type => :rvalue, :doc => <<-EOS
This function converts an array into a hash.
*Examples:*
hash(['a',1,'b',2,'c',3])
Would return: {'a'=>1,'b'=>2,'c'=>3}
EOS
) do |arguments|
raise(Puppet::ParseError, "hash(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'hash(): Requires array to work with')
end
result = {}
begin
# This is to make it compatible with older version of Ruby ...
array = array.flatten
result = Hash[*array]
rescue Exception
raise(Puppet::ParseError, 'hash(): Unable to compute ' +
'hash from array given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -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 :

View file

@ -0,0 +1,22 @@
#
# is_array.rb
#
module Puppet::Parser::Functions
newfunction(:is_array, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is an array.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_array(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
type = arguments[0]
result = type.is_a?(Array)
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,22 @@
#
# is_bool.rb
#
module Puppet::Parser::Functions
newfunction(:is_bool, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a boolean.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_bool(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
type = arguments[0]
result = type.is_a?(TrueClass) || type.is_a?(FalseClass)
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,50 @@
#
# is_domain_name.rb
#
module Puppet::Parser::Functions
newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a syntactically correct domain name.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
domain = arguments[0]
# 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 == '.'
# Remove the final dot, if present.
domain.chomp!('.')
# Check the whole domain
return false if domain.empty?
return false if domain.length > domain_max_length
# Check each label in the domain
labels = domain.split('.')
vlabels = labels.each do |label|
break if label.length < label_min_length
break if label.length > label_max_length
break if label[-1..-1] == '-'
break if label[0..0] == '-'
break unless /^[a-z\d-]+$/i.match(label)
end
return vlabels == labels
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,30 @@
#
# is_float.rb
#
module Puppet::Parser::Functions
newfunction(:is_float, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a float.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_float(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
# Only allow Numeric or String types
return false unless value.is_a?(Numeric) or value.is_a?(String)
if value != value.to_f.to_s and !value.is_a? Float then
return false
else
return true
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,26 @@
#
# is_function_available.rb
#
module Puppet::Parser::Functions
newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS
This function accepts a string as an argument, determines whether the
Puppet runtime has access to a function by that name. It returns a
true if the function exists, false if not.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
# Only allow String types
return false unless arguments[0].is_a?(String)
function = Puppet::Parser::Functions.function(arguments[0].to_sym)
function.is_a?(String) and not function.empty?
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,22 @@
#
# is_hash.rb
#
module Puppet::Parser::Functions
newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a hash.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
type = arguments[0]
result = type.is_a?(Hash)
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,45 @@
#
# is_integer.rb
#
module Puppet::Parser::Functions
newfunction(:is_integer, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is an Integer or
a decimal (base 10) integer in String form. The string may
start with a '-' (minus). A value of '0' is allowed, but a leading '0' digit may not
be followed by other digits as this indicates that the value is octal (base 8).
If given any other argument `false` is returned.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_integer(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
# Regex is taken from the lexer of puppet
# puppet/pops/parser/lexer.rb but modified to match also
# negative values and disallow numbers prefixed with multiple
# 0's
#
# TODO these parameter should be a constant but I'm not sure
# if there is no risk to declare it inside of the module
# Puppet::Parser::Functions
# Integer numbers like
# -1234568981273
# 47291
numeric = %r{^-?(?:(?:[1-9]\d*)|0)$}
if value.is_a? Integer or (value.is_a? String and value.match numeric)
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,32 @@
#
# is_ip_address.rb
#
module Puppet::Parser::Functions
newfunction(:is_ip_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid IP address.
EOS
) do |arguments|
require 'ipaddr'
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_ip_address(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
begin
ip = IPAddr.new(arguments[0])
rescue ArgumentError
return false
end
if ip.ipv4? or ip.ipv6? then
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,27 @@
#
# is_mac_address.rb
#
module Puppet::Parser::Functions
newfunction(:is_mac_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid mac address.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
mac = arguments[0]
if /^[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}$/.match(mac) then
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,75 @@
#
# is_numeric.rb
#
module Puppet::Parser::Functions
newfunction(:is_numeric, :type => :rvalue, :doc => <<-EOS
Returns true if the given argument is a Numeric (Integer or Float),
or a String containing either a valid integer in decimal base 10 form, or
a valid floating point string representation.
The function recognizes only decimal (base 10) integers and float but not
integers in hex (base 16) or octal (base 8) form.
The string representation may start with a '-' (minus). If a decimal '.' is used,
it must be followed by at least one digit.
Valid examples:
77435
10e-12
-8475
0.2343
-23.561e3
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_numeric(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
# Regex is taken from the lexer of puppet
# puppet/pops/parser/lexer.rb but modified to match also
# negative values and disallow invalid octal numbers or
# numbers prefixed with multiple 0's (except in hex numbers)
#
# TODO these parameters should be constants but I'm not sure
# if there is no risk to declare them inside of the module
# Puppet::Parser::Functions
# TODO decide if this should be used
# HEX numbers like
# 0xaa230F
# 0X1234009C
# 0x0012
# -12FcD
#numeric_hex = %r{^-?0[xX][0-9A-Fa-f]+$}
# TODO decide if this should be used
# OCTAL numbers like
# 01234567
# -045372
#numeric_oct = %r{^-?0[1-7][0-7]*$}
# Integer/Float numbers like
# -0.1234568981273
# 47291
# 42.12345e-12
numeric = %r{^-?(?:(?:[1-9]\d*)|0)(?:\.\d+)?(?:[eE]-?\d+)?$}
if value.is_a? Numeric or (value.is_a? String and (
value.match(numeric) #or
# value.match(numeric_hex) or
# value.match(numeric_oct)
))
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,26 @@
#
# is_string.rb
#
module Puppet::Parser::Functions
newfunction(:is_string, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a string.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_string(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
type = arguments[0]
result = type.is_a?(String)
if result and (type == type.to_f.to_s or type == type.to_i.to_s) then
return false
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,41 @@
#
# join.rb
#
module Puppet::Parser::Functions
newfunction(:join, :type => :rvalue, :doc => <<-EOS
This function joins an array into a string using a separator.
*Examples:*
join(['a','b','c'], ",")
Would result in: "a,b,c"
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "join(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'join(): Requires array to work with')
end
suffix = arguments[1] if arguments[1]
if suffix
unless suffix.is_a?(String)
raise(Puppet::ParseError, 'join(): Requires string to work with')
end
end
result = suffix ? array.join(suffix) : array.join
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,47 @@
#
# join.rb
#
module Puppet::Parser::Functions
newfunction(:join_keys_to_values, :type => :rvalue, :doc => <<-EOS
This function joins each key of a hash to that key's corresponding value with a
separator. Keys and values are cast to strings. The return value is an array in
which each element is one joined key/value pair.
*Examples:*
join_keys_to_values({'a'=>1,'b'=>2}, " is ")
Would result in: ["a is 1","b is 2"]
EOS
) do |arguments|
# Validate the number of arguments.
if arguments.size != 2
raise(Puppet::ParseError, "join_keys_to_values(): Takes exactly two " +
"arguments, but #{arguments.size} given.")
end
# Validate the first argument.
hash = arguments[0]
if not hash.is_a?(Hash)
raise(TypeError, "join_keys_to_values(): The first argument must be a " +
"hash, but a #{hash.class} was given.")
end
# Validate the second argument.
separator = arguments[1]
if not separator.is_a?(String)
raise(TypeError, "join_keys_to_values(): The second argument must be a " +
"string, but a #{separator.class} was given.")
end
# Join the keys to their values.
hash.map do |k,v|
String(k) + separator + String(v)
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,26 @@
#
# keys.rb
#
module Puppet::Parser::Functions
newfunction(:keys, :type => :rvalue, :doc => <<-EOS
Returns the keys of a hash as an array.
EOS
) do |arguments|
raise(Puppet::ParseError, "keys(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
hash = arguments[0]
unless hash.is_a?(Hash)
raise(Puppet::ParseError, 'keys(): Requires hash to work with')
end
result = hash.keys
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,20 @@
module Puppet::Parser::Functions
newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Load a YAML file containing an array, string, or hash, and return the data
in the corresponding native data type.
For example:
$myhash = loadyaml('/etc/puppet/data/myhash.yaml')
ENDHEREDOC
unless args.length == 1
raise Puppet::ParseError, ("loadyaml(): wrong number of arguments (#{args.length}; must be 1)")
end
YAML.load_file(args[0])
end
end

View file

@ -0,0 +1,33 @@
#
# lstrip.rb
#
module Puppet::Parser::Functions
newfunction(:lstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the left of a string.
EOS
) do |arguments|
raise(Puppet::ParseError, "lstrip(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'lstrip(): 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) ? i.lstrip : i }
else
result = value.lstrip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,21 @@
module Puppet::Parser::Functions
newfunction(:max, :type => :rvalue, :doc => <<-EOS
Returns the highest value of all arguments.
Requires at least one argument.
EOS
) do |args|
raise(Puppet::ParseError, "max(): Wrong number of arguments " +
"need at least one") if args.size == 0
# Sometimes we get numbers as numerics and sometimes as strings.
# We try to compare them as numbers when possible
return args.max do |a,b|
if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
a.to_f <=> b.to_f
else
a.to_s <=> b.to_s
end
end
end
end

View file

@ -0,0 +1,44 @@
#
# member.rb
#
# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
module Puppet::Parser::Functions
newfunction(:member, :type => :rvalue, :doc => <<-EOS
This function determines if a variable is a member of an array.
*Examples:*
member(['a','b'], 'b')
Would return: true
member(['a','b'], 'c')
Would return: false
EOS
) do |arguments|
raise(Puppet::ParseError, "member(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'member(): Requires array to work with')
end
item = arguments[1]
raise(Puppet::ParseError, 'member(): You must provide item ' +
'to search for within array given') if item.empty?
result = array.include?(item)
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,34 @@
module Puppet::Parser::Functions
newfunction(:merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Merges two or more hashes together and returns the resulting hash.
For example:
$hash1 = {'one' => 1, 'two', => 2}
$hash2 = {'two' => 'dos', 'three', => 'tres'}
$merged_hash = merge($hash1, $hash2)
# The resulting hash is equivalent to:
# $merged_hash = {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
When there is a duplicate key, the key in the rightmost hash will "win."
ENDHEREDOC
if args.length < 2
raise Puppet::ParseError, ("merge(): wrong number of arguments (#{args.length}; must be at least 2)")
end
# The hash we accumulate into
accumulator = Hash.new
# Merge into the accumulator hash
args.each do |arg|
next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
unless arg.is_a?(Hash)
raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
end
accumulator.merge!(arg)
end
# Return the fully merged hash
accumulator
end
end

View file

@ -0,0 +1,21 @@
module Puppet::Parser::Functions
newfunction(:min, :type => :rvalue, :doc => <<-EOS
Returns the lowest value of all arguments.
Requires at least one argument.
EOS
) do |args|
raise(Puppet::ParseError, "min(): Wrong number of arguments " +
"need at least one") if args.size == 0
# Sometimes we get numbers as numerics and sometimes as strings.
# We try to compare them as numbers when possible
return args.min do |a,b|
if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
a.to_f <=> b.to_f
else
a.to_s <=> b.to_s
end
end
end
end

View file

@ -0,0 +1,43 @@
#
# num2bool.rb
#
module Puppet::Parser::Functions
newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
This function converts a number or a string representation of a number into a
true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0
become true.
EOS
) do |arguments|
raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
number = arguments[0]
case number
when Numeric
# Yay, it's a number
when String
begin
number = Float(number)
rescue ArgumentError => ex
raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}")
end
else
begin
number = number.to_s
rescue NoMethodError => ex
raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}")
end
end
# Truncate Floats
number = number.to_i
# Return true for any positive number and false otherwise
return number > 0
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,24 @@
#
# parsejson.rb
#
module Puppet::Parser::Functions
newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
This function accepts JSON as a string and converts into the correct Puppet
structure.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
json = arguments[0]
# PSON is natively available in puppet
PSON.load(json)
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,24 @@
#
# parseyaml.rb
#
module Puppet::Parser::Functions
newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
This function accepts YAML as a string and converts it into the correct
Puppet structure.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
require 'yaml'
YAML::load(arguments[0])
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,29 @@
module Puppet::Parser::Functions
newfunction(:pick, :type => :rvalue, :doc => <<-EOS
This function is similar to a coalesce function in SQL in that it will return
the first value in a list of values that is not undefined or an empty string
(two things in Puppet that will return a boolean false value). Typically,
this function is used to check for a value in the Puppet Dashboard/Enterprise
Console, and failover to a default value like the following:
$real_jenkins_version = pick($::jenkins_version, '1.449')
The value of $real_jenkins_version will first look for a top-scope variable
called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
Enterprise Console are brought into Puppet as top-scope variables), and,
failing that, will use a default value of 1.449.
EOS
) do |args|
args = args.compact
args.delete(:undef)
args.delete(:undefined)
args.delete("")
if args[0].to_s.empty? then
fail Puppet::ParseError, "pick(): must receive at least one non empty value"
else
return args[0]
end
end
end

View file

@ -0,0 +1,35 @@
module Puppet::Parser::Functions
newfunction(:pick_default, :type => :rvalue, :doc => <<-EOS
This function is similar to a coalesce function in SQL in that it will return
the first value in a list of values that is not undefined or an empty string
(two things in Puppet that will return a boolean false value). If no value is
found, it will return the last argument.
Typically, this function is used to check for a value in the Puppet
Dashboard/Enterprise Console, and failover to a default value like the
following:
$real_jenkins_version = pick_default($::jenkins_version, '1.449')
The value of $real_jenkins_version will first look for a top-scope variable
called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
Enterprise Console are brought into Puppet as top-scope variables), and,
failing that, will use a default value of 1.449.
Note that, contrary to the pick() function, the pick_default does not fail if
all arguments are empty. This allows pick_default to use an empty value as
default.
EOS
) do |args|
fail "Must receive at least one argument." if args.empty?
default = args.last
args = args[0..-2].compact
args.delete(:undef)
args.delete(:undefined)
args.delete("")
args << default
return args[0]
end
end

View file

@ -0,0 +1,45 @@
#
# prefix.rb
#
module Puppet::Parser::Functions
newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
This function applies a prefix to all elements in an array.
*Examples:*
prefix(['a','b','c'], 'p')
Will return: ['pa','pb','pc']
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
end
prefix = arguments[1] if arguments[1]
if prefix
unless prefix.is_a?(String)
raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{prefix.inspect}"
end
end
# Turn everything into string same as join would do ...
result = array.collect do |i|
i = i.to_s
prefix ? prefix + i : i
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,88 @@
#
# range.rb
#
# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
module Puppet::Parser::Functions
newfunction(:range, :type => :rvalue, :doc => <<-EOS
When given range in the form of (start, stop) it will extrapolate a range as
an array.
*Examples:*
range("0", "9")
Will return: [0,1,2,3,4,5,6,7,8,9]
range("00", "09")
Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
integers automatically)
range("a", "c")
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|
# We support more than one argument but at least one is mandatory ...
raise(Puppet::ParseError, "range(): Wrong number of " +
"arguments given (#{arguments.size} for 1)") if arguments.size < 1
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 ...
elsif arguments.size > 0
value = arguments[0]
if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
start = m[1]
stop = m[3]
type = m[2]
elsif value.match(/^.+$/)
raise(Puppet::ParseError, 'range(): Unable to compute range ' +
'from the value given')
else
raise(Puppet::ParseError, 'range(): Unknown format of range given')
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
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 ...
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,31 @@
#
# reject.rb
#
module Puppet::Parser::Functions
newfunction(:reject, :type => :rvalue, :doc => <<-EOS) do |args|
This function searches through an array and rejects all elements that match
the provided regular expression.
*Examples:*
reject(['aaa','bbb','ccc','aaaddd'], 'aaa')
Would return:
['bbb','ccc']
EOS
if (args.size != 2)
raise Puppet::ParseError,
"reject(): Wrong number of arguments given #{args.size} for 2"
end
ary = args[0]
pattern = Regexp.new(args[1])
ary.reject { |e| e =~ pattern }
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,28 @@
#
# reverse.rb
#
module Puppet::Parser::Functions
newfunction(:reverse, :type => :rvalue, :doc => <<-EOS
Reverses the order of a string or array.
EOS
) do |arguments|
raise(Puppet::ParseError, "reverse(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'reverse(): Requires either ' +
'array or string to work with')
end
result = value.reverse
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,32 @@
#
# rstrip.rb
#
module Puppet::Parser::Functions
newfunction(:rstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the right of the string.
EOS
) do |arguments|
raise(Puppet::ParseError, "rstrip(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'rstrip(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
result = value.collect { |i| i.is_a?(String) ? i.rstrip : i }
else
result = value.rstrip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,46 @@
#
# shuffle.rb
#
module Puppet::Parser::Functions
newfunction(:shuffle, :type => :rvalue, :doc => <<-EOS
Randomizes the order of a string or array elements.
EOS
) do |arguments|
raise(Puppet::ParseError, "shuffle(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'shuffle(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# Check whether it makes sense to shuffle ...
return result if result.size <= 1
# We turn any string value into an array to be able to shuffle ...
result = string ? result.split('') : result
elements = result.size
# Simple implementation of FisherYates in-place shuffle ...
elements.times do |i|
j = rand(elements - i) + i
result[j], result[i] = result[i], result[j]
end
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,48 @@
#
# size.rb
#
# TODO(Krzysztof Wilczynski): Support for hashes would be nice too ...
module Puppet::Parser::Functions
newfunction(:size, :type => :rvalue, :doc => <<-EOS
Returns the number of elements in a string or array.
EOS
) do |arguments|
raise(Puppet::ParseError, "size(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
item = arguments[0]
if item.is_a?(String)
begin
#
# Check whether your item is a numeric value or not ...
# This will take care about positive and/or negative numbers
# for both integer and floating-point values ...
#
# Please note that Puppet has no notion of hexadecimal
# nor octal numbers for its DSL at this point in time ...
#
Float(item)
raise(Puppet::ParseError, 'size(): Requires either ' +
'string or array to work with')
rescue ArgumentError
result = item.size
end
elsif item.is_a?(Array)
result = item.size
else
raise(Puppet::ParseError, 'size(): Unknown type given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,27 @@
#
# sort.rb
#
module Puppet::Parser::Functions
newfunction(:sort, :type => :rvalue, :doc => <<-EOS
Sorts strings and arrays lexically.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "sort(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
if value.is_a?(Array) then
value.sort
elsif value.is_a?(String) then
value.split("").sort.join("")
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,36 @@
#
# squeeze.rb
#
module Puppet::Parser::Functions
newfunction(:squeeze, :type => :rvalue, :doc => <<-EOS
Returns a new string where runs of the same character that occur in this set are replaced by a single character.
EOS
) do |arguments|
if ((arguments.size != 2) and (arguments.size != 1)) then
raise(Puppet::ParseError, "squeeze(): Wrong number of arguments "+
"given #{arguments.size} for 2 or 1")
end
item = arguments[0]
squeezeval = arguments[1]
if item.is_a?(Array) then
if squeezeval then
item.collect { |i| i.squeeze(squeezeval) }
else
item.collect { |i| i.squeeze }
end
else
if squeezeval then
item.squeeze(squeezeval)
else
item.squeeze
end
end
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,46 @@
#
# str2bool.rb
#
module Puppet::Parser::Functions
newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
This converts a string to a boolean. This attempt to convert strings that
contain things like: y, 1, t, true to 'true' and strings that contain things
like: 0, f, n, false, no to 'false'.
EOS
) do |arguments|
raise(Puppet::ParseError, "str2bool(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
string = arguments[0]
# If string is already Boolean, return it
if !!string == string
return string
end
unless string.is_a?(String)
raise(Puppet::ParseError, 'str2bool(): Requires either ' +
'string to work with')
end
# We consider all the yes, no, y, n and so on too ...
result = case string
#
# 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, 'str2bool(): Unknown type of boolean given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,32 @@
#
# str2saltedsha512.rb
#
module Puppet::Parser::Functions
newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
This converts a string to a salted-SHA512 password hash (which is used for
OS X versions >= 10.7). Given any simple string, you will get a hex version
of a salted-SHA512 password hash that can be inserted into your Puppet
manifests as a valid password attribute.
EOS
) do |arguments|
require 'digest/sha2'
raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
"passed (#{arguments.size} but we require 1)") if arguments.size != 1
password = arguments[0]
unless password.is_a?(String)
raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
"String argument, you passed: #{password.class}")
end
seedint = rand(2**31 - 1)
seedstring = Array(seedint).pack("L")
saltedpass = Digest::SHA512.digest(seedstring + password)
(seedstring + saltedpass).unpack('H*')[0]
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,107 @@
#
# strftime.rb
#
module Puppet::Parser::Functions
newfunction(:strftime, :type => :rvalue, :doc => <<-EOS
This function returns formatted time.
*Examples:*
To return the time since epoch:
strftime("%s")
To return the date:
strftime("%Y-%m-%d")
*Format meaning:*
%a - The abbreviated weekday name (``Sun'')
%A - The full weekday name (``Sunday'')
%b - The abbreviated month name (``Jan'')
%B - The full month name (``January'')
%c - The preferred local date and time representation
%C - Century (20 in 2009)
%d - Day of the month (01..31)
%D - Date (%m/%d/%y)
%e - Day of the month, blank-padded ( 1..31)
%F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
%h - Equivalent to %b
%H - Hour of the day, 24-hour clock (00..23)
%I - Hour of the day, 12-hour clock (01..12)
%j - Day of the year (001..366)
%k - hour, 24-hour clock, blank-padded ( 0..23)
%l - hour, 12-hour clock, blank-padded ( 0..12)
%L - Millisecond of the second (000..999)
%m - Month of the year (01..12)
%M - Minute of the hour (00..59)
%n - Newline (\n)
%N - Fractional seconds digits, default is 9 digits (nanosecond)
%3N millisecond (3 digits)
%6N microsecond (6 digits)
%9N nanosecond (9 digits)
%p - Meridian indicator (``AM'' or ``PM'')
%P - Meridian indicator (``am'' or ``pm'')
%r - time, 12-hour (same as %I:%M:%S %p)
%R - time, 24-hour (%H:%M)
%s - Number of seconds since 1970-01-01 00:00:00 UTC.
%S - Second of the minute (00..60)
%t - Tab character (\t)
%T - time, 24-hour (%H:%M:%S)
%u - Day of the week as a decimal, Monday being 1. (1..7)
%U - Week number of the current year,
starting with the first Sunday as the first
day of the first week (00..53)
%v - VMS date (%e-%b-%Y)
%V - Week number of year according to ISO 8601 (01..53)
%W - Week number of the current year,
starting with the first Monday as the first
day of the first week (00..53)
%w - Day of the week (Sunday is 0, 0..6)
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%y - Year without a century (00..99)
%Y - Year with century
%z - Time zone as hour offset from UTC (e.g. +0900)
%Z - Time zone name
%% - Literal ``%'' character
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "strftime(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
format = arguments[0]
raise(Puppet::ParseError, 'strftime(): You must provide ' +
'format for evaluation') if format.empty?
# The Time Zone argument is optional ...
time_zone = arguments[1] if arguments[1]
time = Time.new
# There is probably a better way to handle Time Zone ...
if time_zone and not time_zone.empty?
original_zone = ENV['TZ']
local_time = time.clone
local_time = local_time.utc
ENV['TZ'] = time_zone
time = local_time.localtime
ENV['TZ'] = original_zone
end
result = time.strftime(format)
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,39 @@
#
# strip.rb
#
module Puppet::Parser::Functions
newfunction(:strip, :type => :rvalue, :doc => <<-EOS
This function removes leading and trailing whitespace from a string or from
every string inside an array.
*Examples:*
strip(" aaa ")
Would result in: "aaa"
EOS
) do |arguments|
raise(Puppet::ParseError, "strip(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'strip(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
result = value.collect { |i| i.is_a?(String) ? i.strip : i }
else
result = value.strip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,45 @@
#
# suffix.rb
#
module Puppet::Parser::Functions
newfunction(:suffix, :type => :rvalue, :doc => <<-EOS
This function applies a suffix to all elements in an array.
*Examples:*
suffix(['a','b','c'], 'p')
Will return: ['ap','bp','cp']
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "suffix(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}"
end
suffix = arguments[1] if arguments[1]
if suffix
unless suffix.is_a? String
raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}"
end
end
# Turn everything into string same as join would do ...
result = array.collect do |i|
i = i.to_s
suffix ? i + suffix : i
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,39 @@
#
# swapcase.rb
#
module Puppet::Parser::Functions
newfunction(:swapcase, :type => :rvalue, :doc => <<-EOS
This function will swap the existing case of a string.
*Examples:*
swapcase("aBcD")
Would result in: "AbCd"
EOS
) do |arguments|
raise(Puppet::ParseError, "swapcase(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'swapcase(): 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) ? i.swapcase : i }
else
result = value.swapcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,49 @@
#
# time.rb
#
module Puppet::Parser::Functions
newfunction(:time, :type => :rvalue, :doc => <<-EOS
This function will return the current time since epoch as an integer.
*Examples:*
time()
Will return something like: 1311972653
EOS
) do |arguments|
# The Time Zone argument is optional ...
time_zone = arguments[0] if arguments[0]
if (arguments.size != 0) and (arguments.size != 1) then
raise(Puppet::ParseError, "time(): Wrong number of arguments "+
"given #{arguments.size} for 0 or 1")
end
time = Time.new
# There is probably a better way to handle Time Zone ...
if time_zone and not time_zone.empty?
original_zone = ENV['TZ']
local_time = time.clone
local_time = local_time.utc
ENV['TZ'] = time_zone
time = local_time.localtime
ENV['TZ'] = original_zone
end
# Calling Time#to_i on a receiver changes it. Trust me I am the Doctor.
result = time.strftime('%s')
result = result.to_i
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,28 @@
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.
EOS
) do |arguments|
raise(Puppet::ParseError, "to_bytes(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
arg = arguments[0]
return arg if arg.is_a? Numeric
value,prefix = */([0-9.e+-]*)\s*([^bB]?)/.match(arg)[1,2]
value = value.to_f
case prefix
when '' then return value.to_i
when 'k' then return (value*(1<<10)).to_i
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
else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
end
end
end

View file

@ -0,0 +1,50 @@
#
# type.rb
#
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
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 ...
# 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 :

View file

@ -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 :

View file

@ -0,0 +1,51 @@
#
# unique.rb
#
module Puppet::Parser::Functions
newfunction(:unique, :type => :rvalue, :doc => <<-EOS
This function will remove duplicates from strings and arrays.
*Examples:*
unique("aabbcc")
Will return:
abc
You can also use this with arrays:
unique(["a","a","b","b","c","c"])
This returns:
["a","b","c"]
EOS
) do |arguments|
raise(Puppet::ParseError, "unique(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'unique(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# We turn any string value into an array to be able to shuffle ...
result = string ? result.split('') : result
result = result.uniq # Remove duplicates ...
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,41 @@
#
# upcase.rb
#
module Puppet::Parser::Functions
newfunction(:upcase, :type => :rvalue, :doc => <<-EOS
Converts a string or an array of strings to uppercase.
*Examples:*
upcase("abcd")
Will return:
ASDF
EOS
) do |arguments|
raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
"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')
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 }
else
result = value.upcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,35 @@
#
# uriescape.rb
#
require 'uri'
module Puppet::Parser::Functions
newfunction(:uriescape, :type => :rvalue, :doc => <<-EOS
Urlencodes a string or array of strings.
Requires either a single string or an array as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "uriescape(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
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 }
else
result = URI.escape(value)
end
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,56 @@
module Puppet::Parser::Functions
newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args|
Validate the string represents an absolute path in the filesystem. This function works
for windows and unix style paths.
The following values will pass:
$my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
validate_absolute_path($my_path)
$my_path2 = "/var/lib/puppet"
validate_absolute_path($my_path2)
The following values will fail, causing compilation to abort:
validate_absolute_path(true)
validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
$undefined = undef
validate_absolute_path($undefined)
ENDHEREDOC
require 'puppet/util'
unless args.length > 0 then
raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)")
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.")
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
end

View file

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are array data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_array = [ 'one', 'two' ]
validate_array($my_array)
The following values will fail, causing compilation to abort:
validate_array(true)
validate_array('some_string')
$undefined = undef
validate_array($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_array(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless arg.is_a?(Array)
raise Puppet::ParseError, ("#{arg.inspect} is not an Array. It looks to be a #{arg.class}")
end
end
end
end

View file

@ -0,0 +1,81 @@
module Puppet::Parser::Functions
newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
Perform validation of a string using an Augeas lens
The first argument of this function should be a string to
test, and the second argument should be the name of the Augeas lens to use.
If Augeas fails to parse the string with the lens, the compilation will
abort with a parse error.
A third argument can be specified, listing paths which should
not be found in the file. The `$file` variable points to the location
of the temporary file being tested in the Augeas tree.
For example, if you want to make sure your passwd content never contains
a user `foo`, you could write:
validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
Or if you wanted to ensure that no users used the '/bin/barsh' shell,
you could use:
validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
If a fourth argument is specified, this will be the error message raised and
seen by the user.
A helpful error message can be returned like this:
validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
ENDHEREDOC
unless Puppet.features.augeas?
raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.")
end
if (args.length < 2) or (args.length > 4) then
raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)")
end
msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}"
require 'augeas'
aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
begin
content = args[0]
# Test content in a temporary file
tmpfile = Tempfile.new("validate_augeas")
begin
tmpfile.write(content)
ensure
tmpfile.close
end
# Check for syntax
lens = args[1]
aug.transform(
:lens => lens,
:name => 'Validate_augeas',
:incl => tmpfile.path
)
aug.load!
unless aug.match("/augeas/files#{tmpfile.path}//error").empty?
error = aug.get("/augeas/files#{tmpfile.path}//error/message")
msg += " with error: #{error}"
raise Puppet::ParseError, (msg)
end
# Launch unit tests
tests = args[2] || []
aug.defvar('file', "/files#{tmpfile.path}")
tests.each do |t|
msg += " testing path #{t}"
raise Puppet::ParseError, (msg) unless aug.match(t).empty?
end
ensure
aug.close
tmpfile.unlink
end
end
end

View file

@ -0,0 +1,34 @@
module Puppet::Parser::Functions
newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are either true or false. Abort catalog
compilation if any value fails this check.
The following values will pass:
$iamtrue = true
validate_bool(true)
validate_bool(true, true, false, $iamtrue)
The following values will fail, causing compilation to abort:
$some_array = [ true ]
validate_bool("false")
validate_bool("true")
validate_bool($some_array)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_bool(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless function_is_bool([arg])
raise Puppet::ParseError, ("#{arg.inspect} is not a boolean. It looks to be a #{arg.class}")
end
end
end
end

View file

@ -0,0 +1,48 @@
require 'puppet/util/execution'
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.
If a third argument is specified, this will be the error message raised and
seen by the user.
A helpful error message can be returned like this:
Example:
validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers 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)")
end
msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}"
content = args[0]
checkscript = args[1]
# Test content in a temporary file
tmpfile = Tempfile.new("validate_cmd")
begin
tmpfile.write(content)
tmpfile.close
if Puppet::Util::Execution.respond_to?('execute')
Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}")
else
Puppet::Util.execute("#{checkscript} #{tmpfile.path}")
end
rescue Puppet::ExecutionFailure => detail
msg += "\n#{detail}"
raise Puppet::ParseError, msg
ensure
tmpfile.unlink
end
end
end

View file

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are hash data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_hash = { 'one' => 'two' }
validate_hash($my_hash)
The following values will fail, causing compilation to abort:
validate_hash(true)
validate_hash('some_string')
$undefined = undef
validate_hash($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_hash(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless arg.is_a?(Hash)
raise Puppet::ParseError, ("#{arg.inspect} is not a Hash. It looks to be a #{arg.class}")
end
end
end
end

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,40 @@
module Puppet::Parser::Functions
newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
Perform simple validation of a string against one or more regular
expressions. The first argument of this function should be a string to
test, and the second argument should be a stringified regular expression
(without the // delimiters) or an array of regular expressions. If none
of the regular expressions match the string passed in, 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.
The following strings will validate against the regular expressions:
validate_re('one', '^one$')
validate_re('one', [ '^one', '^two' ])
The following strings will fail to validate, causing compilation to abort:
validate_re('one', [ '^two', '^three' ])
A helpful error message can be returned like this:
validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
ENDHEREDOC
if (args.length < 2) or (args.length > 3) then
raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
end
msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
# We're using a flattened array here because we can't call String#any? in
# Ruby 1.9 like we can in Ruby 1.8
raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str|
args[0] =~ Regexp.compile(re_str)
end
end
end

View file

@ -0,0 +1,71 @@
module Puppet::Parser::Functions
newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
Validate that the first argument is a string (or an array of strings), and
less/equal to than the length of the second argument. An optional third
parameter can be given a the minimum length. It fails if the first
argument is not a string or array of strings, and if arg 2 and arg 3 are
not convertable to a number.
The following values will pass:
validate_slength("discombobulate",17)
validate_slength(["discombobulate","moo"],17)
validate_slength(["discombobulate","moo"],17,3)
The following valueis will not:
validate_slength("discombobulate",1)
validate_slength(["discombobulate","thermometer"],5)
validate_slength(["discombobulate","moo"],17,10)
ENDHEREDOC
raise Puppet::ParseError, "validate_slength(): Wrong number of arguments (#{args.length}; must be 2 or 3)" unless args.length == 2 or args.length == 3
input, max_length, min_length = *args
begin
max_length = Integer(max_length)
raise ArgumentError if max_length <= 0
rescue ArgumentError, TypeError
raise Puppet::ParseError, "validate_slength(): Expected second argument to be a positive Numeric, got #{max_length}:#{max_length.class}"
end
if min_length
begin
min_length = Integer(min_length)
raise ArgumentError if min_length < 0
rescue ArgumentError, TypeError
raise Puppet::ParseError, "validate_slength(): Expected third argument to be unset or a positive Numeric, got #{min_length}:#{min_length.class}"
end
else
min_length = 0
end
if min_length > max_length
raise Puppet::ParseError, "validate_slength(): Expected second argument to be larger than third argument"
end
validator = lambda do |str|
unless str.length <= max_length and str.length >= min_length
raise Puppet::ParseError, "validate_slength(): Expected length of #{input.inspect} to be between #{min_length} and #{max_length}, was #{input.length}"
end
end
case input
when String
validator.call(input)
when Array
input.each_with_index do |arg, pos|
if arg.is_a? String
validator.call(arg)
else
raise Puppet::ParseError, "validate_slength(): Expected element at array position #{pos} to be a String, got #{arg.class}"
end
end
else
raise Puppet::ParseError, "validate_slength(): Expected first argument to be a String or Array, got #{input.class}"
end
end
end

View file

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are string data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_string = "one two"
validate_string($my_string, 'three')
The following values will fail, causing compilation to abort:
validate_string(true)
validate_string([ 'some', 'array' ])
$undefined = undef
validate_string($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_string(): 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. It looks to be a #{arg.class}")
end
end
end
end

View file

@ -0,0 +1,39 @@
#
# values.rb
#
module Puppet::Parser::Functions
newfunction(:values, :type => :rvalue, :doc => <<-EOS
When given a hash this function will return the values of that hash.
*Examples:*
$hash = {
'a' => 1,
'b' => 2,
'c' => 3,
}
values($hash)
This example would return:
[1,2,3]
EOS
) do |arguments|
raise(Puppet::ParseError, "values(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
hash = arguments[0]
unless hash.is_a?(Hash)
raise(Puppet::ParseError, 'values(): Requires hash to work with')
end
result = hash.values
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,98 @@
#
# values_at.rb
#
module Puppet::Parser::Functions
newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
Finds value inside an array based on location.
The first argument is the array you want to analyze, and the second element can
be a combination of:
* A single numeric index
* A range in the form of 'start-stop' (eg. 4-9)
* An array combining the above
*Examples*:
values_at(['a','b','c'], 2)
Would return ['c'].
values_at(['a','b','c'], ["0-1"])
Would return ['a','b'].
values_at(['a','b','c','d','e'], [0, "2-3"])
Would return ['a','c','d'].
EOS
) do |arguments|
raise(Puppet::ParseError, "values_at(): Wrong number of " +
"arguments given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments.shift
unless array.is_a?(Array)
raise(Puppet::ParseError, 'values_at(): Requires array to work with')
end
indices = [arguments.shift].flatten() # Get them all ... Pokemon ...
if not indices or indices.empty?
raise(Puppet::ParseError, 'values_at(): You must provide ' +
'at least one positive index to collect')
end
result = []
indices_list = []
indices.each do |i|
if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
start = m[1].to_i
stop = m[3].to_i
type = m[2]
if start > stop
raise(Puppet::ParseError, 'values_at(): Stop index in ' +
'given indices range is smaller than the start index')
elsif stop > array.size - 1 # First element is at index 0 is it not?
raise(Puppet::ParseError, 'values_at(): Stop index in ' +
'given indices range exceeds array size')
end
range = case type
when /^(\.\.|\-)$/ then (start .. stop)
when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
end
range.each { |i| indices_list << i.to_i }
else
# Only positive numbers allowed in this case ...
if not i.match(/^\d+$/)
raise(Puppet::ParseError, 'values_at(): Unknown format ' +
'of given index')
end
# In Puppet numbers are often string-encoded ...
i = i.to_i
if i > array.size - 1 # Same story. First element is at index 0 ...
raise(Puppet::ParseError, 'values_at(): Given index ' +
'exceeds array size')
end
indices_list << i
end
end
# We remove nil values as they make no sense in Puppet DSL ...
result = indices_list.collect { |i| array[i] }.compact
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,65 @@
#
# zip.rb
#
module Puppet::Parser::Functions
newfunction(:zip, :type => :rvalue, :doc => <<-EOS
Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.
*Example:*
zip(['1','2','3'],['4','5','6'])
Would result in:
["1", "4"], ["2", "5"], ["3", "6"]
EOS
) do |arguments|
# Technically we support three arguments but only first is mandatory ...
raise(Puppet::ParseError, "zip(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
a = arguments[0]
b = arguments[1]
unless a.is_a?(Array) and b.is_a?(Array)
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
result = a.zip(b)
result = flatten ? result.flatten : result
return result
end
end
# vim: set ts=2 sw=2 et :

View file

@ -0,0 +1,83 @@
Puppet::Type.type(:file_line).provide(:ruby) do
def exists?
lines.find do |line|
line.chomp == resource[:line].chomp
end
end
def create
if resource[:match]
handle_create_with_match
elsif resource[:after]
handle_create_with_after
else
append_line
end
end
def destroy
local_lines = lines
File.open(resource[:path],'w') do |fh|
fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
end
end
private
def lines
# If this type is ever used with very large files, we should
# write this in a different way, using a temp
# file; for now assuming that this type is only used on
# small-ish config files that can fit into memory without
# too much trouble.
@lines ||= File.readlines(resource[:path])
end
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 && 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)
end
if (match_count == 0)
fh.puts(resource[:line])
end
end
end
def handle_create_with_after
regex = Regexp.new(resource[:after])
count = lines.count {|l| l.match(regex)}
case count
when 1 # find the line to put our line after
File.open(resource[:path], 'w') do |fh|
lines.each do |l|
fh.puts(l)
if regex.match(l) then
fh.puts(resource[:line])
end
end
end
when 0 # append the line to the end of the file
append_line
else
raise Puppet::Error, "#{count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern."
end
end
##
# append the line to the file.
#
# @api private
def append_line
File.open(resource[:path], 'a') do |fh|
fh.puts resource[:line]
end
end
end

View file

@ -0,0 +1,46 @@
Puppet::Type.newtype(:anchor) do
desc <<-'ENDOFDESC'
A simple resource type intended to be used as an anchor in a composite class.
In Puppet 2.6, when a class declares another class, the resources in the
interior class are not contained by the exterior class. This interacts badly
with the pattern of composing complex modules from smaller classes, as it
makes it impossible for end users to specify order relationships between the
exterior class and other modules.
The anchor type lets you work around this. By sandwiching any interior
classes between two no-op resources that _are_ contained by the exterior
class, you can ensure that all resources in the module are contained.
class ntp {
# These classes will have the correct order relationship with each
# other. However, without anchors, they won't have any order
# relationship to Class['ntp'].
class { 'ntp::package': }
-> class { 'ntp::config': }
-> class { 'ntp::service': }
# These two resources "anchor" the composed classes within the ntp
# class.
anchor { 'ntp::begin': } -> Class['ntp::package']
Class['ntp::service'] -> anchor { 'ntp::end': }
}
This allows the end user of the ntp module to establish require and before
relationships with Class['ntp']:
class { 'ntp': } -> class { 'mcollective': }
class { 'mcollective': } -> class { 'ntp': }
ENDOFDESC
newparam :name do
desc "The name of the anchor resource."
end
def refresh
# We don't do anything with them, but we need this to
# show that we are "refresh aware" and not break the
# chain of propagation.
end
end

View file

@ -0,0 +1,79 @@
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.
Example:
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}
In this example, Puppet will ensure both of the specified lines are
contained in the file /etc/sudoers.
EOT
ensurable do
defaultvalues
defaultto :present
end
newparam(:name, :namevar => true) do
desc 'An arbitrary name used as the identity of the resource.'
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.'
end
newparam(:multiple) do
desc 'An optional value to determine if match can change multiple lines.'
newvalues(true, false)
end
newparam(:after) do
desc 'An optional value used to specify the line after which we will add any new lines. (Existing lines are added in place)'
end
newparam(:line) do
desc 'The line to be appended to the file located by the path parameter.'
end
newparam(:path) do
desc 'The file Puppet will ensure contains the line specified by the line parameter.'
validate do |value|
unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
end
end
end
# Autorequire the file resource if it's being managed
autorequire(:file) do
self[:path]
end
validate 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