diff options
author | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2018-09-20 14:50:39 +0200 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2018-09-20 14:50:39 +0200 |
commit | 6162b571d3dea04957ba6712a4191b83c8fb2c89 (patch) | |
tree | b77e271107d885984ba2ec394c908ca5519f7558 /code/environments/production/modules/stdlib/lib/puppet | |
parent | 3f1bbf87bbcc3daa15cd7391b2949b5bf742781b (diff) | |
download | puppet.FWSECK-6162b571d3dea04957ba6712a4191b83c8fb2c89.tar.gz puppet.FWSECK-6162b571d3dea04957ba6712a4191b83c8fb2c89.tar.bz2 puppet.FWSECK-6162b571d3dea04957ba6712a4191b83c8fb2c89.zip |
Bundles puppetlabs-stdlib 4.25.1.
Diffstat (limited to 'code/environments/production/modules/stdlib/lib/puppet')
171 files changed, 6454 insertions, 0 deletions
diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/deprecation.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/deprecation.rb new file mode 100644 index 0000000..af6109d --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/deprecation.rb @@ -0,0 +1,32 @@ +# Function to print deprecation warnings, Logs a warning once for a given key. The uniqueness key - can appear once. +# The msg is the message text including any positional information that is formatted by the user/caller of the method. +# It is affected by the puppet setting 'strict', which can be set to :error (outputs as an error message), +# :off (no message / error is displayed) and :warning (default, outputs a warning) *Type*: String, String. +# + +Puppet::Functions.create_function(:deprecation) do + dispatch :deprecation do + param 'String', :key + param 'String', :message + end + + def deprecation(key, message) + if defined? Puppet::Pops::PuppetStack.stacktrace + stacktrace = Puppet::Pops::PuppetStack.stacktrace() + file = stacktrace[0] + line = stacktrace[1] + message = "#{message} at #{file}:#{line}" + end + # depending on configuration setting of strict + case Puppet.settings[:strict] + when :off # rubocop:disable Lint/EmptyWhen : Is required to prevent false errors + # do nothing + when :error + raise("deprecation. #{key}. #{message}") + else + unless ENV['STDLIB_LOG_DEPRECATIONS'] == 'false' + Puppet.deprecation_warning(message, key) + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/fact.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/fact.rb new file mode 100644 index 0000000..48736ad --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/fact.rb @@ -0,0 +1,57 @@ +# Digs into the facts hash using dot-notation +# +# Example usage: +# +# fact('osfamily') +# fact('os.architecture') +# +# Array indexing: +# +# fact('mountpoints."/dev".options.1') +# +# Fact containing a "." in the name: +# +# fact('vmware."VRA.version"') +# +Puppet::Functions.create_function(:fact) do + dispatch :fact do + param 'String', :fact_name + end + + def to_dot_syntax(array_path) + array_path.map { |string| + string.include?('.') ? %("#{string}") : string + }.join('.') + end + + def fact(fact_name) + facts = closure_scope['facts'] + + # Transform the dot-notation string into an array of paths to walk. Make + # sure to correctly extract double-quoted values containing dots as single + # elements in the path. + path = fact_name.scan(%r{([^."]+)|(?:")([^"]+)(?:")}).map { |x| x.compact.first } + + walked_path = [] + path.reduce(facts) do |d, k| + return nil if d.nil? || k.nil? + + if d.is_a?(Array) + begin + result = d[Integer(k)] + rescue ArgumentError => e # rubocop:disable Lint/UselessAssignment : Causes errors if assigment is removed. + Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is an array; cannot index to '#{k}'") + result = nil + end + elsif d.is_a?(Hash) + result = d[k] + else + Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is not a collection; cannot walk to '#{k}'") + result = nil + end + + walked_path << k + result + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_a.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_a.rb new file mode 100644 index 0000000..24b9744 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_a.rb @@ -0,0 +1,32 @@ +# Boolean check to determine whether a variable is of a given data type. This is equivalent to the `=~` type checks. +# +# @example how to check a data type +# # check a data type +# foo = 3 +# $bar = [1,2,3] +# $baz = 'A string!' +# +# if $foo.is_a(Integer) { +# notify { 'foo!': } +# } +# if $bar.is_a(Array) { +# notify { 'bar!': } +# } +# if $baz.is_a(String) { +# notify { 'baz!': } +# } +# +# See the documentation for "The Puppet Type System" for more information about types. +# See the `assert_type()` function for flexible ways to assert the type of a value. +# +Puppet::Functions.create_function(:is_a) do + dispatch :is_a do + param 'Any', :value + param 'Type', :type + end + + def is_a(value, type) # rubocop:disable Style/PredicateName : Used in to many other places to rename at this time, attempting to refactor caused Rubocop to crash. + # See puppet's lib/puppet/pops/evaluator/evaluator_impl.rb eval_MatchExpression + Puppet::Pops::Types::TypeCalculator.instance?(type, value) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_absolute_path.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_absolute_path.rb new file mode 100644 index 0000000..c9d92eb --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_absolute_path.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_absolute_path) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_absolute_path', 'This method is deprecated, please use match expressions with Stdlib::Compat::Absolute_Path instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_absolute_path', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_array.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_array.rb new file mode 100644 index 0000000..fdc60dd --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_array.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_array) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_array', 'This method is deprecated, please use match expressions with Stdlib::Compat::Array instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_array', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_bool.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_bool.rb new file mode 100644 index 0000000..1672f0a --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_bool.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_bool) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_bool', 'This method is deprecated, please use match expressions with Stdlib::Compat::Bool instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_bool', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_float.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_float.rb new file mode 100644 index 0000000..03e94d3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_float.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_float) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_float', 'This method is deprecated, please use match expressions with Stdlib::Compat::Float instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_float', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_ip_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ip_address.rb new file mode 100644 index 0000000..1ab67e7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ip_address.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_ip_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_ip_address', 'This method is deprecated, please use match expressions with Stdlib::Compat::Ip_address instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_ip_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv4_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv4_address.rb new file mode 100644 index 0000000..034f9ba --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv4_address.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_ipv4_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_ipv4_address', 'This method is deprecated, please use match expressions with Stdlib::Compat::Ipv4 instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_ipv4_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv6_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv6_address.rb new file mode 100644 index 0000000..c8fb3ab --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_ipv6_address.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_ipv6_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_ipv4_address', 'This method is deprecated, please use match expressions with Stdlib::Compat::Ipv6 instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_ipv6_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_numeric.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_numeric.rb new file mode 100644 index 0000000..79a6bbf --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_numeric.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_numeric) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_numeric', 'This method is deprecated, please use match expressions with Stdlib::Compat::Numeric instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_numeric', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/is_string.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/is_string.rb new file mode 100644 index 0000000..a32216c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/is_string.rb @@ -0,0 +1,17 @@ +Puppet::Functions.create_function(:is_string) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'is_string', 'This method is deprecated, please use match expressions with Stdlib::Compat::String instead. They are described at https://docs.puppet.com/puppet/latest/reference/lang_data_type.html#match-expressions.') + scope.send('function_is_string', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/length.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/length.rb new file mode 100644 index 0000000..8cd43e5 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/length.rb @@ -0,0 +1,14 @@ +# A function to eventually replace the old size() function for stdlib - The original size function did not handle Puppets new type capabilities, so this function is a Puppet 4 compatible solution. +Puppet::Functions.create_function(:length) do + dispatch :length do + param 'Variant[String,Array,Hash]', :value + end + def length(value) + if value.is_a?(String) + result = value.length + elsif value.is_a?(Array) || value.is_a?(Hash) + result = value.size + end + result + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/sprintf_hash.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/sprintf_hash.rb new file mode 100644 index 0000000..2536bc9 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/sprintf_hash.rb @@ -0,0 +1,29 @@ +# Uses sprintf with named references. +# +# The first parameter is format string describing how the rest of the parameters in the hash +# should be formatted. See the documentation for the `Kernel::sprintf` function in Ruby for +# all the details. +# +# In the given argument hash with parameters, all keys are converted to symbols so they work +# with the `sprintf` function. +# +# @example Format a string and number +# $output = sprintf_hash('String: %<foo>s / number converted to binary: %<number>b', +# { 'foo' => 'a string', 'number' => 5 }) +# # $output = 'String: a string / number converted to binary: 101' +# +Puppet::Functions.create_function(:sprintf_hash) do + # @param format The format to use. + # @param arguments Hash with parameters. + # @return The formatted string. + dispatch :sprintf_hash do + param 'String', :format + param 'Hash', :arguments + # Disabled for now. This gives issues on puppet 4.7.1. + # return_type 'String' + end + + def sprintf_hash(format, arguments) + Kernel.sprintf(format, Hash[arguments.map { |(k, v)| [k.to_sym, v] }]) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/to_json.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/to_json.rb new file mode 100644 index 0000000..782d695 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/to_json.rb @@ -0,0 +1,21 @@ +# Take a data structure and output it as JSON +# +# @example how to output JSON +# # output json to a file +# file { '/tmp/my.json': +# ensure => file, +# content => to_json($myhash), +# } +# +# +require 'json' + +Puppet::Functions.create_function(:to_json) do + dispatch :to_json do + param 'Any', :data + end + + def to_json(data) + data.to_json + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/to_json_pretty.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/to_json_pretty.rb new file mode 100644 index 0000000..a7a1458 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/to_json_pretty.rb @@ -0,0 +1,38 @@ +# Take a data structure and output it as pretty JSON +# +# @example how to output pretty JSON +# # output pretty json to a file +# file { '/tmp/my.json': +# ensure => file, +# content => to_json_pretty($myhash), +# } +# +# @example how to output pretty JSON skipping over keys with undef values +# # output pretty JSON to a file skipping over undef values +# file { '/tmp/my.json': +# ensure => file, +# content => to_json_pretty({ +# param_one => 'value', +# param_two => undef, +# }), +# } +# +require 'json' + +Puppet::Functions.create_function(:to_json_pretty) do + dispatch :to_json_pretty do + param 'Variant[Hash, Array]', :data + optional_param 'Boolean', :skip_undef + end + + def to_json_pretty(data, skip_undef = false) + if skip_undef + if data.is_a? Array + data = data.reject { |value| value.nil? } + elsif data.is_a? Hash + data = data.reject { |_, value| value.nil? } + end + end + JSON.pretty_generate(data) << "\n" + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/to_yaml.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/to_yaml.rb new file mode 100644 index 0000000..fdd7370 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/to_yaml.rb @@ -0,0 +1,21 @@ +# Take a data structure and output it as YAML +# +# @example how to output YAML +# # output yaml to a file +# file { '/tmp/my.yaml': +# ensure => file, +# content => to_yaml($myhash), +# } +# +# +require 'yaml' + +Puppet::Functions.create_function(:to_yaml) do + dispatch :to_yaml do + param 'Any', :data + end + + def to_yaml(data) + data.to_yaml + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/type_of.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/type_of.rb new file mode 100644 index 0000000..5bed6d5 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/type_of.rb @@ -0,0 +1,19 @@ +# Returns the type when passed a value. +# +# @example how to compare values' types +# # compare the types of two values +# if type_of($first_value) != type_of($second_value) { fail("first_value and second_value are different types") } +# @example how to compare against an abstract type +# unless type_of($first_value) <= Numeric { fail("first_value must be Numeric") } +# unless type_of{$first_value) <= Collection[1] { fail("first_value must be an Array or Hash, and contain at least one element") } +# +# See the documentation for "The Puppet Type System" for more information about types. +# See the `assert_type()` function for flexible ways to assert the type of a value. +# +# The built-in type() function in puppet is generally preferred over this function +# this function is provided for backwards compatibility. +Puppet::Functions.create_function(:type_of) do + def type_of(value) + Puppet::Pops::Types::TypeCalculator.infer_set(value) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_absolute_path.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_absolute_path.rb new file mode 100644 index 0000000..44f600f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_absolute_path.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_absolute_path) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_absolute_path', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Absolute_Path. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_absolute_path', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_array.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_array.rb new file mode 100644 index 0000000..2bedd3f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_array.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_array) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_array', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Array. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_array', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_bool.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_bool.rb new file mode 100644 index 0000000..907eed3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_bool.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_bool) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_bool', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Bool. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_bool', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_hash.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_hash.rb new file mode 100644 index 0000000..c6a61a4 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_hash.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_hash) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_hash', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Hash. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_hash', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_integer.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_integer.rb new file mode 100644 index 0000000..487dcf7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_integer.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_integer) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_integer', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Integer. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_integer', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ip_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ip_address.rb new file mode 100644 index 0000000..68e7f7f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ip_address.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_ip_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_ip_address', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ip_Address. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_ip_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv4_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv4_address.rb new file mode 100644 index 0000000..caeeaca --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv4_address.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_ipv4_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_ipv4_address', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv4_Address. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_ipv4_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv6_address.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv6_address.rb new file mode 100644 index 0000000..c035357 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_ipv6_address.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_ipv6_address) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff + # -c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_ipv6_address', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv6_address. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_ipv6_address', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_legacy.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_legacy.rb new file mode 100644 index 0000000..21646ad --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_legacy.rb @@ -0,0 +1,62 @@ +Puppet::Functions.create_function(:validate_legacy) do + # The function checks a value against both the target_type (new) and the previous_validation function (old). + + dispatch :validate_legacy do + param 'Any', :scope + param 'Type', :target_type + param 'String', :function_name + param 'Any', :value + repeated_param 'Any', :args + end + + dispatch :validate_legacy_s do + param 'Any', :scope + param 'String', :type_string + param 'String', :function_name + param 'Any', :value + repeated_param 'Any', :args + end + + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff- + # c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def validate_legacy_s(scope, type_string, *args) + t = Puppet::Pops::Types::TypeParser.new.parse(type_string, scope) + validate_legacy(scope, t, *args) + end + + def validate_legacy(scope, target_type, function_name, value, *prev_args) + if assert_type(target_type, value) + if previous_validation(scope, function_name, value, *prev_args) + # Silently passes + else + Puppet.notice("Accepting previously invalid value for target type '#{target_type}'") + end + else + inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value) + error_msg = Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch("validate_legacy(#{function_name})", target_type, inferred_type) + if previous_validation(scope, function_name, value, *prev_args) + call_function('deprecation', 'validate_legacy', error_msg) + else + call_function('fail', error_msg) + end + end + end + + def previous_validation(scope, function_name, value, *prev_args) + # Call the previous validation function and catch any errors. Return true if no errors are thrown. + + scope.send("function_#{function_name}".to_s, [value, *prev_args]) + true + rescue Puppet::ParseError + false + end + + def assert_type(type, value) + Puppet::Pops::Types::TypeCalculator.instance?(type, value) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_numeric.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_numeric.rb new file mode 100644 index 0000000..3adb0a8 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_numeric.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_numeric) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff- + # c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_numeric', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Numeric. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_numeric', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_re.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_re.rb new file mode 100644 index 0000000..d357aab --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_re.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_re) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff- + # c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_re', 'This method is deprecated, please use the stdlib validate_legacy function, + with Pattern[]. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_re', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_slength.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_slength.rb new file mode 100644 index 0000000..ad6f7b3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_slength.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_slength) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff- + # c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_slength', 'This method is deprecated, please use the stdlib validate_legacy function, + with String[]. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_slength', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/functions/validate_string.rb b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_string.rb new file mode 100644 index 0000000..a908c19 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/functions/validate_string.rb @@ -0,0 +1,18 @@ +Puppet::Functions.create_function(:validate_string) do + dispatch :deprecation_gen do + param 'Any', :scope + repeated_param 'Any', :args + end + # Workaround PUP-4438 (fixed: https://github.com/puppetlabs/puppet/commit/e01c4dc924cd963ff6630008a5200fc6a2023b08#diff- + # c937cc584953271bb3d3b3c2cb141790R221) to support puppet < 4.1.0 and puppet < 3.8.1. + def call(scope, *args) + manipulated_args = [scope] + args + self.class.dispatcher.dispatch(self, scope, manipulated_args) + end + + def deprecation_gen(scope, *args) + call_function('deprecation', 'validate_string', 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::String. There is further documentation for validate_legacy function in the README.') + scope.send('function_validate_string', args) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/abs.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/abs.rb new file mode 100644 index 0000000..84bef8c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/abs.rb @@ -0,0 +1,33 @@ +# +# abs.rb +# +module Puppet::Parser::Functions + newfunction(:abs, :type => :rvalue, :doc => <<-DOC + Returns the absolute value of a number, for example -34.56 becomes + 34.56. Takes a single integer and float value as an argument. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "abs(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + # Numbers in Puppet are often string-encoded which is troublesome ... + if value.is_a?(String) + if value =~ %r{^-?(?:\d+)(?:\.\d+){1}$} + value = value.to_f + elsif value =~ %r{^-?\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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2array.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2array.rb new file mode 100644 index 0000000..510c2d5 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2array.rb @@ -0,0 +1,29 @@ +# +# any2array.rb +# +module Puppet::Parser::Functions + newfunction(:any2array, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + if arguments.empty? + return [] + end + + return arguments unless arguments.length == 1 + return arguments[0] if arguments[0].is_a?(Array) + if arguments[0].is_a?(Hash) + result = [] + arguments[0].each do |key, value| + result << key << value + end + return result + end + return arguments + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2bool.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2bool.rb new file mode 100644 index 0000000..9eb634d --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/any2bool.rb @@ -0,0 +1,53 @@ +# +# any2bool.rb +# +module Puppet::Parser::Functions + newfunction(:any2bool, :type => :rvalue, :doc => <<-DOC + This converts 'anything' to a boolean. In practise it does the following: + + * Strings such as Y,y,1,T,t,TRUE,yes,'true' will return true + * Strings such as 0,F,f,N,n,FALSE,no,'false' will return false + * Booleans will just return their original value + * Number (or a string representation of a number) > 0 will return true, otherwise false + * undef will return false + * Anything else will return true + DOC + ) do |arguments| + + raise(Puppet::ParseError, "any2bool(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + # If argument is already Boolean, return it + if !!arguments[0] == arguments[0] # rubocop:disable Style/DoubleNegation : Could not find a better way to check if a boolean + return arguments[0] + end + + arg = arguments[0] + + if arg.nil? + return false + end + + if arg == :undef + return false + end + + valid_float = begin + !!Float(arg) # rubocop:disable Style/DoubleNegation : Could not find a better way to check if a boolean + rescue + false + end + + if arg.is_a?(Numeric) + return function_num2bool([arguments[0]]) + end + + if arg.is_a?(String) + return function_num2bool([arguments[0]]) if valid_float + return function_str2bool([arguments[0]]) + end + + return true + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/assert_private.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/assert_private.rb new file mode 100644 index 0000000..9cdebb9 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/assert_private.rb @@ -0,0 +1,27 @@ +# +# assert_private.rb +# +module Puppet::Parser::Functions + newfunction(:assert_private, :doc => <<-DOC + Sets the current class or definition as private. + Calling the class or definition from outside the current module will fail. + DOC + ) do |args| + + raise(Puppet::ParseError, "assert_private(): Wrong number of arguments given (#{args.size}}) for 0 or 1)") if args.size > 1 + + scope = self + if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name') + message = nil + if args[0] && args[0].is_a?(String) + message = args[0] + else + manifest_name = scope.source.name + manifest_type = scope.source.type + message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition' + message += " #{manifest_name} is private" + end + raise(Puppet::ParseError, message) + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/base64.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/base64.rb new file mode 100644 index 0000000..484c2f1 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/base64.rb @@ -0,0 +1,67 @@ +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +module Puppet::Parser::Functions + newfunction(:base64, :type => :rvalue, :doc => <<-'DOC') 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') + + # explicitly define encode/decode method: default, strict, urlsafe + $method = 'default' + $encodestring = base64('encode', 'thestring', $method) + $decodestring = base64('decode', 'dGhlc3RyaW5n', $method) + + DOC + + require 'base64' + + raise Puppet::ParseError, "base64(): Wrong number of arguments (#{args.length}; must be >= 2)" unless args.length >= 2 + + actions = %w[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 + + method = %w[default strict urlsafe] + + chosen_method = if args.length <= 2 + 'default' + else + args[2] + end + + unless method.include?(chosen_method) + raise Puppet::ParseError, "base64(): the third argument must be one of 'default', 'strict', or 'urlsafe'" + end + + case args[0] + when 'encode' + case chosen_method + when 'default' + result = Base64.encode64(args[1]) + when 'strict' + result = Base64.strict_encode64(args[1]) + when 'urlsafe' + result = Base64.urlsafe_encode64(args[1]) + end + when 'decode' + case chosen_method + when 'default' + result = Base64.decode64(args[1]) + when 'strict' + result = Base64.strict_decode64(args[1]) + when 'urlsafe' + result = Base64.urlsafe_decode64(args[1]) + end + end + + return result + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/basename.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/basename.rb new file mode 100644 index 0000000..b717fa1 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/basename.rb @@ -0,0 +1,24 @@ +# +# basename.rb +# +module Puppet::Parser::Functions + newfunction(:basename, :type => :rvalue, :doc => <<-DOC + Strips directory (and optional suffix) from a filename + DOC + ) do |arguments| + + raise(Puppet::ParseError, 'basename(): No arguments given') if arguments.empty? + raise(Puppet::ParseError, "basename(): Too many arguments given (#{arguments.size})") if arguments.size > 2 + raise(Puppet::ParseError, 'basename(): Requires string as first argument') unless arguments[0].is_a?(String) + + rv = File.basename(arguments[0]) if arguments.size == 1 + if arguments.size == 2 + raise(Puppet::ParseError, 'basename(): Requires string as second argument') unless arguments[1].is_a?(String) + rv = File.basename(arguments[0], arguments[1]) + end + + return rv + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2num.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2num.rb new file mode 100644 index 0000000..e8ad961 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2num.rb @@ -0,0 +1,24 @@ +# +# bool2num.rb +# +module Puppet::Parser::Functions + newfunction(:bool2num, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "bool2num(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = function_str2bool([arguments[0]]) + + # We have real boolean values as well ... + result = value ? 1 : 0 + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2str.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2str.rb new file mode 100644 index 0000000..502ab2e --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/bool2str.rb @@ -0,0 +1,43 @@ +# +# bool2str.rb +# +module Puppet::Parser::Functions + newfunction(:bool2str, :type => :rvalue, :doc => <<-DOC + Converts a boolean to a string using optionally supplied arguments. The + optional second and third arguments represent what true and false will be + converted to respectively. If only one argument is given, it will be + converted from a boolean to a string containing 'true' or 'false'. + + *Examples:* + + bool2str(true) => 'true' + bool2str(true, 'yes', 'no') => 'yes' + bool2str(false, 't', 'f') => 'f' + + Requires a single boolean as an input. + DOC + ) do |arguments| + + unless arguments.size == 1 || arguments.size == 3 + raise(Puppet::ParseError, "bool2str(): Wrong number of arguments given (#{arguments.size} for 3)") + end + + value = arguments[0] + true_string = arguments[1] || 'true' + false_string = arguments[2] || 'false' + klass = value.class + + # We can have either true or false, and nothing else + unless [FalseClass, TrueClass].include?(klass) + raise(Puppet::ParseError, 'bool2str(): Requires a boolean to work with') + end + + unless [true_string, false_string].all? { |x| x.is_a?(String) } + raise(Puppet::ParseError, 'bool2str(): Requires strings to convert to') + end + + return value ? true_string : false_string + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/camelcase.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/camelcase.rb new file mode 100644 index 0000000..fdc54a2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/camelcase.rb @@ -0,0 +1,31 @@ +# +# camelcase.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:camelcase, :type => :rvalue, :doc => <<-DOC + Converts the case of a string or all strings in an array to camel case. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "camelcase(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + klass = value.class + + unless [Array, String].include?(klass) + raise(Puppet::ParseError, 'camelcase(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.split('_').map { |e| e.capitalize }.join : i } + else + value.split('_').map { |e| e.capitalize }.join + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/capitalize.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/capitalize.rb new file mode 100644 index 0000000..7d7703f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/capitalize.rb @@ -0,0 +1,29 @@ +# +# capitalize.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:capitalize, :type => :rvalue, :doc => <<-DOC + Capitalizes the first letter of a string or array of strings. + Requires either a single string or an array as an input. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "capitalize(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'capitalize(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.capitalize : i } + else + value.capitalize + end + + return result + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ceiling.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ceiling.rb new file mode 100644 index 0000000..d0323a8 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ceiling.rb @@ -0,0 +1,25 @@ +# +# ceiling.rb +# +module Puppet::Parser::Functions + newfunction(:ceiling, :type => :rvalue, :doc => <<-DOC + Returns the smallest integer greater or equal to the argument. + Takes a single numeric value as an argument. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "ceiling(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + begin + arg = Float(arguments[0]) + rescue TypeError, ArgumentError => _e + raise(Puppet::ParseError, "ceiling(): Wrong argument type given (#{arguments[0]} for Numeric)") + end + + raise(Puppet::ParseError, "ceiling(): Wrong argument type given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false + + arg.ceil + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chomp.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chomp.rb new file mode 100644 index 0000000..0e9cd6d --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chomp.rb @@ -0,0 +1,31 @@ +# +# chomp.rb +# +module Puppet::Parser::Functions + newfunction(:chomp, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "chomp(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'chomp(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.chomp : i } + else + value.chomp + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chop.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chop.rb new file mode 100644 index 0000000..80e8964 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/chop.rb @@ -0,0 +1,33 @@ +# +# chop.rb +# +module Puppet::Parser::Functions + newfunction(:chop, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "chop(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'chop(): Requires either an array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.chop : i } + else + value.chop + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/clamp.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/clamp.rb new file mode 100644 index 0000000..0aea511 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/clamp.rb @@ -0,0 +1,28 @@ +# +# clamp.rb +# +module Puppet::Parser::Functions + newfunction(:clamp, :type => :rvalue, :arity => -2, :doc => <<-DOC + Clamps value to a range. + DOC + ) do |args| + + args.flatten! + + raise(Puppet::ParseError, 'clamp(): Wrong number of arguments, need three to clamp') if args.size != 3 + + # check values out + args.each do |value| + case [value.class] + when [String] + raise(Puppet::ParseError, "clamp(): Required explicit numeric (#{value}:String)") unless value =~ %r{^\d+$} + when [Hash] + raise(Puppet::ParseError, "clamp(): The Hash type is not allowed (#{value})") + end + end + + # convert to numeric each element + # then sort them and get a middle value + args.map { |n| n.to_i }.sort[1] + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/concat.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/concat.rb new file mode 100644 index 0000000..9a83ec1 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/concat.rb @@ -0,0 +1,39 @@ +# +# concat.rb +# +module Puppet::Parser::Functions + newfunction(:concat, :type => :rvalue, :doc => <<-DOC + Appends the contents of multiple arrays into array 1. + + *Example:* + + concat(['1','2','3'],['4','5','6'],['7','8','9']) + + Would result in: + + ['1','2','3','4','5','6','7','8','9'] + DOC + ) do |arguments| + + # Check that more than 2 arguments have been given ... + raise(Puppet::ParseError, "concat(): Wrong number of arguments given (#{arguments.size} for < 2)") if arguments.size < 2 + + a = arguments[0] + + # Check that the first parameter is an array + unless a.is_a?(Array) + raise(Puppet::ParseError, 'concat(): Requires array to work with') + end + + result = a + arguments.shift + + arguments.each do |x| + result += (x.is_a?(Array) ? x : [x]) + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/convert_base.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/convert_base.rb new file mode 100644 index 0000000..6d17f85 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/convert_base.rb @@ -0,0 +1,36 @@ +# +# convert_base.rb +# +module Puppet::Parser::Functions + newfunction(:convert_base, :type => :rvalue, :arity => 2, :doc => <<-'DOC') do |args| + Converts a given integer or base 10 string representing an integer to a specified base, as a string. + + Usage: + + $binary_repr = convert_base(5, 2) # $binary_repr is now set to "101" + $hex_repr = convert_base("254", "16") # $hex_repr is now set to "fe" + + DOC + + raise Puppet::ParseError, 'convert_base(): First argument must be either a string or an integer' unless args[0].is_a?(Integer) || args[0].is_a?(String) + raise Puppet::ParseError, 'convert_base(): Second argument must be either a string or an integer' unless args[1].is_a?(Integer) || args[1].is_a?(String) + + if args[0].is_a?(String) + raise Puppet::ParseError, 'convert_base(): First argument must be an integer or a string corresponding to an integer in base 10' unless args[0] =~ %r{^[0-9]+$} + end + + if args[1].is_a?(String) + raise Puppet::ParseError, 'convert_base(): First argument must be an integer or a string corresponding to an integer in base 10' unless args[1] =~ %r{^[0-9]+$} + end + + number_to_convert = args[0] + new_base = args[1] + + number_to_convert = number_to_convert.to_i + new_base = new_base.to_i + + raise Puppet::ParseError, 'convert_base(): base must be at least 2 and must not be greater than 36' unless new_base >= 2 && new_base <= 36 + + return number_to_convert.to_s(new_base) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/count.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/count.rb new file mode 100644 index 0000000..f5ac8c3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/count.rb @@ -0,0 +1,24 @@ +# +# count.rb +# +module Puppet::Parser::Functions + newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-DOC + 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. + DOC + ) do |args| + + if args.size > 2 + raise(ArgumentError, "count(): Wrong number of arguments given #{args.size} for 1 or 2.") + end + + collection, item = args + + if item + collection.count item + else + collection.count { |obj| !obj.nil? && obj != :undef && obj != '' } + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb new file mode 100644 index 0000000..dd70c61 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb @@ -0,0 +1,47 @@ +# +# deep_merge.rb +# +module Puppet::Parser::Functions + newfunction(:deep_merge, :type => :rvalue, :doc => <<-'DOC') 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." + + DOC + + if args.length < 2 + raise Puppet::ParseError, "deep_merge(): wrong number of arguments (#{args.length}; must be at least 2)" + end + + deep_merge = proc 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 = {} + args.each do |arg| + next if arg.is_a?(String) && 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb new file mode 100644 index 0000000..1383308 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb @@ -0,0 +1,57 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:defined_with_params, + :type => :rvalue, + :doc => <<-'DOC' + 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, } + } +DOC + ) do |vals| + reference, params = vals + raise(ArgumentError, 'Must specify a reference') unless reference + if !params || params == '' + params = {} + end + ret = false + + if Puppet::Util::Package.versioncmp(Puppet.version, '4.6.0') >= 0 + # Workaround for PE-20308 + if reference.is_a?(String) + type_name, title = Puppet::Resource.type_and_title(reference, nil) + type = Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_resource_type_or_class(find_global_scope, type_name.downcase) + elsif reference.is_a?(Puppet::Resource) + type = reference.resource_type + title = reference.title + else + raise(ArgumentError, "Reference is not understood: '#{reference.class}'") + end + # end workaround + else + type = reference.to_s + title = nil + end + + resource = findresource(type, title) + if resource + matches = params.map do |key, value| + # eql? avoids bugs caused by monkeypatching in puppet + resource_is_undef = resource[key].eql?(:undef) || resource[key].nil? + value_is_undef = value.eql?(:undef) || value.nil? + (resource_is_undef && value_is_undef) || (resource[key] == value) + end + ret = params.empty? || !matches.include?(false) + end + Puppet.debug("Resource #{reference} was not determined to be defined") + ret +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete.rb new file mode 100644 index 0000000..f83ff16 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete.rb @@ -0,0 +1,42 @@ +# +# delete.rb +# +module Puppet::Parser::Functions + newfunction(:delete, :type => :rvalue, :doc => <<-DOC + 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({'a'=>1,'b'=>2,'c'=>3}, ['b','c']) + Would return: {'a'=>1} + + delete('abracadabra', 'bra') + Would return: 'acada' + DOC + ) do |arguments| + + raise(Puppet::ParseError, "delete(): Wrong number of arguments given #{arguments.size} for 2") unless arguments.size == 2 + + collection = arguments[0].dup + Array(arguments[1]).each do |item| + case collection + when Array, Hash + collection.delete item + when String + collection.gsub! item, '' + else + raise(TypeError, "delete(): First argument must be an Array, String, or Hash. Given an argument of class #{collection.class}.") + end + end + collection + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_at.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_at.rb new file mode 100644 index 0000000..e40ad26 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_at.rb @@ -0,0 +1,45 @@ +# +# delete_at.rb +# +module Puppet::Parser::Functions + newfunction(:delete_at, :type => :rvalue, :doc => <<-DOC + Deletes a determined indexed value from an array. + + *Examples:* + + delete_at(['a','b','c'], 1) + + Would return: ['a','c'] + DOC + ) 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) && !index.match(%r{^\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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_regex.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_regex.rb new file mode 100644 index 0000000..64cad9c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_regex.rb @@ -0,0 +1,43 @@ +# +# delete_regex.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:delete_regex, :type => :rvalue, :doc => <<-DOC + deletes all instances of a given element that match a regular expression + from an array or key from a hash. Multiple regular expressions are assumed + to be matched as an OR. + + *Examples:* + + delete_regex(['a','b','c','b'], 'b') + Would return: ['a','c'] + + delete_regex(['a','b','c','b'], ['b', 'c']) + Would return: ['a'] + + delete_regex({'a'=>1,'b'=>2,'c'=>3}, 'b') + Would return: {'a'=>1,'c'=>3} + + delete_regex({'a'=>1,'b'=>2,'c'=>3}, '^a$') + Would return: {'b'=>2,'c'=>3} + + DOC + ) do |arguments| + + raise(Puppet::ParseError, "delete_regex(): Wrong number of arguments given #{arguments.size} for 2") unless arguments.size == 2 + + collection = arguments[0].dup + Array(arguments[1]).each do |item| + case collection + when Array, Hash, String + collection.reject! { |coll_item| (coll_item =~ %r{\b#{item}\b}) } + else + raise(TypeError, "delete_regex(): First argument must be an Array, Hash, or String. Given an argument of class #{collection.class}.") + end + end + collection + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb new file mode 100644 index 0000000..af2dbc7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb @@ -0,0 +1,34 @@ +# +# delete_undef_values.rb +# +module Puppet::Parser::Functions + newfunction(:delete_undef_values, :type => :rvalue, :doc => <<-DOC + 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] + + DOC + ) do |args| + + raise(Puppet::ParseError, "delete_undef_values(): Wrong number of arguments given (#{args.size})") if args.empty? + + unless args[0].is_a?(Array) || 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_values.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_values.rb new file mode 100644 index 0000000..1192766 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/delete_values.rb @@ -0,0 +1,26 @@ +# +# delete_values.rb +# +module Puppet::Parser::Functions + newfunction(:delete_values, :type => :rvalue, :doc => <<-DOC + 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'} + + DOC + ) do |arguments| + + raise(Puppet::ParseError, "delete_values(): Wrong number of arguments given (#{arguments.size} of 2)") if arguments.size != 2 + + hash, item = arguments + + unless 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deprecation.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deprecation.rb new file mode 100644 index 0000000..01f0deb --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/deprecation.rb @@ -0,0 +1,19 @@ +# +# deprecation.rb +# +module Puppet::Parser::Functions + newfunction(:deprecation, :doc => <<-DOC + Function to print deprecation warnings (this is the 3.X version of it), The uniqueness key - can appear once. The msg is the message text including any positional information that is formatted by the user/caller of the method.). +DOC + ) do |arguments| + + raise(Puppet::ParseError, "deprecation: Wrong number of arguments given (#{arguments.size} for 2)") unless arguments.size == 2 + + key = arguments[0] + message = arguments[1] + + if ENV['STDLIB_LOG_DEPRECATIONS'] == 'true' + warning("deprecation. #{key}. #{message}") + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/difference.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/difference.rb new file mode 100644 index 0000000..cfaebc9 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/difference.rb @@ -0,0 +1,34 @@ +# +# difference.rb +# +module Puppet::Parser::Functions + newfunction(:difference, :type => :rvalue, :doc => <<-DOC + 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"] + DOC + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "difference(): Wrong number of arguments given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'difference(): Requires 2 arrays') + end + + result = first - second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig.rb new file mode 100644 index 0000000..75e83aa --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig.rb @@ -0,0 +1,15 @@ +# +# dig.rb +# +module Puppet::Parser::Functions + newfunction(:dig, :type => :rvalue, :doc => <<-DOC + DEPRECATED: This function has been replaced in Puppet 4.5.0, please use dig44() for backwards compatibility or use the new version. + DOC + ) do |arguments| + warning('dig() DEPRECATED: This function has been replaced in Puppet 4.5.0, please use dig44() for backwards compatibility or use the new version.') + unless Puppet::Parser::Functions.autoloader.loaded?(:dig44) + Puppet::Parser::Functions.autoloader.load(:dig44) + end + function_dig44(arguments) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig44.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig44.rb new file mode 100644 index 0000000..e7e78bf --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dig44.rb @@ -0,0 +1,65 @@ +# +# dig44.rb +# +module Puppet::Parser::Functions + newfunction( + :dig44, + :type => :rvalue, + :arity => -2, + :doc => <<-DOC + DEPRECATED: This function has been replaced in puppet 4.5.0. + + Looks up into a complex structure of arrays and hashes and returns a value + or the default value if nothing was found. + + Key can contain slashes to describe path components. The function will go down + the structure and try to extract the required value. + + $data = { + 'a' => { + 'b' => [ + 'b1', + 'b2', + 'b3', + ] + } + } + + $value = dig44($data, ['a', 'b', '2'], 'not_found') + => $value = 'b3' + + a -> first hash key + b -> second hash key + 2 -> array index starting with 0 + + not_found -> (optional) will be returned if there is no value or the path + did not match. Defaults to nil. + + In addition to the required "key" argument, the function accepts a default + argument. It will be returned if no value was found or a path component is + missing. And the fourth argument can set a variable path separator. + DOC + ) do |arguments| + # Two arguments are required + raise(Puppet::ParseError, "dig44(): Wrong number of arguments given (#{arguments.size} for at least 2)") if arguments.size < 2 + + data, path, default = *arguments + + raise(Puppet::ParseError, "dig44(): first argument must be a hash or an array, given #{data.class.name}") unless data.is_a?(Hash) || data.is_a?(Array) + raise(Puppet::ParseError, "dig44(): second argument must be an array, given #{path.class.name}") unless path.is_a? Array + + value = path.reduce(data) do |structure, key| + break unless structure.is_a?(Hash) || structure.is_a?(Array) + if structure.is_a? Array + begin + key = Integer key + rescue + break + end + end + break if structure[key].nil? || structure[key] == :undef + structure[key] + end + value.nil? ? default : value + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dirname.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dirname.rb new file mode 100644 index 0000000..a243287 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dirname.rb @@ -0,0 +1,24 @@ +# +# dirname.rb +# +module Puppet::Parser::Functions + newfunction(:dirname, :type => :rvalue, :doc => <<-DOC + Returns the dirname of a path. + DOC + ) do |arguments| + + if arguments.empty? + raise(Puppet::ParseError, 'dirname(): No arguments given') + end + if arguments.size > 1 + raise(Puppet::ParseError, "dirname(): Too many arguments given (#{arguments.size})") + end + unless arguments[0].is_a?(String) + raise(Puppet::ParseError, 'dirname(): Requires string as argument') + end + + return File.dirname(arguments[0]) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dos2unix.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dos2unix.rb new file mode 100644 index 0000000..32722ba --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/dos2unix.rb @@ -0,0 +1,15 @@ +# Custom Puppet function to convert dos to unix format +module Puppet::Parser::Functions + newfunction(:dos2unix, :type => :rvalue, :arity => 1, :doc => <<-DOC + Returns the Unix version of the given string. + Takes a single string argument. + DOC + ) do |arguments| + + unless arguments[0].is_a?(String) + raise(Puppet::ParseError, 'dos2unix(): Requires string as argument') + end + + arguments[0].gsub(%r{\r\n}, "\n") + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/downcase.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/downcase.rb new file mode 100644 index 0000000..1661e56 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/downcase.rb @@ -0,0 +1,30 @@ +# +# downcase.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:downcase, :type => :rvalue, :doc => <<-DOC + Converts the case of a string or all strings in an array to lower case. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "downcase(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'downcase(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.downcase : i } + else + value.downcase + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/empty.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/empty.rb new file mode 100644 index 0000000..79c43d0 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/empty.rb @@ -0,0 +1,23 @@ +# +# empty.rb +# +module Puppet::Parser::Functions + newfunction(:empty, :type => :rvalue, :doc => <<-DOC + Returns true if the variable is empty. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "empty(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String) || value.is_a?(Numeric) + raise(Puppet::ParseError, 'empty(): Requires either array, hash, string or integer to work with') + end + + return false if value.is_a?(Numeric) + result = value.empty? + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/enclose_ipv6.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/enclose_ipv6.rb new file mode 100644 index 0000000..f412b01 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/enclose_ipv6.rb @@ -0,0 +1,41 @@ +# +# enclose_ipv6.rb +# +module Puppet::Parser::Functions + newfunction(:enclose_ipv6, :type => :rvalue, :doc => <<-DOC + Takes an array of ip addresses and encloses the ipv6 addresses with square brackets. + DOC + ) do |arguments| + + require 'ipaddr' + + rescuable_exceptions = [ArgumentError] + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + if arguments.size != 1 + raise(Puppet::ParseError, "enclose_ipv6(): Wrong number of arguments given #{arguments.size} for 1") + end + unless arguments[0].is_a?(String) || arguments[0].is_a?(Array) + raise(Puppet::ParseError, "enclose_ipv6(): Wrong argument type given #{arguments[0].class} expected String or Array") + end + + input = [arguments[0]].flatten.compact + result = [] + + input.each do |val| + unless val == '*' + begin + ip = IPAddr.new(val) + rescue *rescuable_exceptions + raise(Puppet::ParseError, "enclose_ipv6(): Wrong argument given #{val} is not an ip address.") + end + val = "[#{ip}]" if ip.ipv6? + end + result << val + end + + return result.uniq + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb new file mode 100644 index 0000000..e1c4f65 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb @@ -0,0 +1,50 @@ +# +# ensure_packages.rb +# +module Puppet::Parser::Functions + newfunction(:ensure_packages, :type => :statement, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "ensure_packages(): Wrong number of arguments given (#{arguments.size} for 1 or 2)") if arguments.size > 2 || arguments.empty? + raise(Puppet::ParseError, 'ensure_packages(): Requires second argument to be a Hash') if arguments.size == 2 && !arguments[1].is_a?(Hash) + + if arguments[0].is_a?(Hash) + if arguments[1] + defaults = { 'ensure' => 'present' }.merge(arguments[1]) + if defaults['ensure'] == 'installed' + defaults['ensure'] = 'present' + end + else + defaults = { 'ensure' => 'present' } + end + + Puppet::Parser::Functions.function(:ensure_resources) + function_ensure_resources(['package', arguments[0].dup, defaults]) + else + packages = Array(arguments[0]) + + if arguments[1] + defaults = { 'ensure' => 'present' }.merge(arguments[1]) + if defaults['ensure'] == 'installed' + defaults['ensure'] = 'present' + end + else + defaults = { 'ensure' => 'present' } + end + + Puppet::Parser::Functions.function(:ensure_resource) + packages.each do |package_name| + raise(Puppet::ParseError, 'ensure_packages(): Empty String provided for package name') if package_name.empty? + unless findresource("Package[#{package_name}]") + function_ensure_resource(['package', package_name, defaults]) + end + end + end + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb new file mode 100644 index 0000000..d28ed9d --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb @@ -0,0 +1,46 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:ensure_resource, + :type => :statement, + :doc => <<-'DOC' + 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'}) + +DOC + ) 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}] with params #{params} not created because it already exists") + else + Puppet.debug("Create new resource #{type}[#{item}] with params #{params}") + Puppet::Parser::Functions.function(:create_resources) + function_create_resources([type.capitalize, { item => params }]) + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resources.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resources.rb new file mode 100644 index 0000000..642247c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/ensure_resources.rb @@ -0,0 +1,50 @@ +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:ensure_resources, + :type => :statement, + :doc => <<-'DOC' + Takes a resource type, title (only hash), and a list of attributes that describe a + resource. + + user { 'dan': + gid => 'mygroup', + ensure => present, + } + + An hash of resources should be passed in and each will be created with + the type and parameters specified if it doesn't already exist. + + ensure_resources('user', {'dan' => { gid => 'mygroup', uid => '600' } , 'alex' => { gid => 'mygroup' }}, {'ensure' => 'present'}) + + From Hiera Backend: + + userlist: + dan: + gid: 'mygroup' + uid: '600' + alex: + gid: 'mygroup' + + Call: + ensure_resources('user', hiera_hash('userlist'), {'ensure' => 'present'}) +DOC + ) do |vals| + type, title, params = vals + raise(ArgumentError, 'Must specify a type') unless type + raise(ArgumentError, 'Must specify a title') unless title + params ||= {} + + raise(Puppet::ParseError, 'ensure_resources(): Requires second argument to be a Hash') unless title.is_a?(Hash) + resource_hash = title.dup + resources = resource_hash.keys + + Puppet::Parser::Functions.function(:ensure_resource) + resources.each do |resource_name| + params_merged = if resource_hash[resource_name] + params.merge(resource_hash[resource_name]) + else + params + end + function_ensure_resource([type, resource_name, params_merged]) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/flatten.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/flatten.rb new file mode 100644 index 0000000..15970df --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/flatten.rb @@ -0,0 +1,31 @@ +# +# flatten.rb +# +module Puppet::Parser::Functions + newfunction(:flatten, :type => :rvalue, :doc => <<-DOC + 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'] + DOC + ) 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/floor.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/floor.rb new file mode 100644 index 0000000..9fcb048 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/floor.rb @@ -0,0 +1,25 @@ +# +# floor.rb +# +module Puppet::Parser::Functions + newfunction(:floor, :type => :rvalue, :doc => <<-DOC + Returns the largest integer less or equal to the argument. + Takes a single numeric value as an argument. + DOC + ) 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rand_string.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rand_string.rb new file mode 100644 index 0000000..ee45236 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rand_string.rb @@ -0,0 +1,35 @@ +Puppet::Parser::Functions.newfunction( + :fqdn_rand_string, + :arity => -2, + :type => :rvalue, + :doc => "Usage: `fqdn_rand_string(LENGTH, [CHARSET], [SEED])`. LENGTH is + required and must be a positive integer. CHARSET is optional and may be + `undef` or a string. SEED is optional and may be any number or string. + + Generates a random string LENGTH characters long using the character set + provided by CHARSET, combining the `$fqdn` fact and the value of SEED for + repeatable randomness. (That is, each node will get a different random + string from this function, but a given node's result will be the same every + time unless its hostname changes.) Adding a SEED can be useful if you need + more than one unrelated string. CHARSET will default to alphanumeric if + `undef` or an empty string.", +) do |args| + raise(ArgumentError, 'fqdn_rand_string(): wrong number of arguments (0 for 1)') if args.empty? + Puppet::Parser::Functions.function('is_integer') + raise(ArgumentError, 'fqdn_rand_string(): first argument must be a positive integer') unless function_is_integer([args[0]]) && args[0].to_i > 0 + raise(ArgumentError, 'fqdn_rand_string(): second argument must be undef or a string') unless args[1].nil? || args[1].is_a?(String) + + Puppet::Parser::Functions.function('fqdn_rand') + + length = args.shift.to_i + charset = args.shift.to_s.chars.to_a + + charset = (0..9).map { |i| i.to_s } + ('A'..'Z').to_a + ('a'..'z').to_a if charset.empty? + + rand_string = '' + for current in 1..length # rubocop:disable Style/For : An each loop would not work correctly in this circumstance + rand_string << charset[function_fqdn_rand([charset.size, (args + [current.to_s]).join(':')]).to_i] + end + + rand_string +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb new file mode 100644 index 0000000..879e44b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb @@ -0,0 +1,59 @@ +# +# fqdn_rotate.rb +# +Puppet::Parser::Functions.newfunction( + :fqdn_rotate, + :type => :rvalue, + :doc => "Usage: `fqdn_rotate(VALUE, [SEED])`. VALUE is required and + must be an array or a string. SEED is optional and may be any number + or string. + + Rotates VALUE a random number of times, combining the `$fqdn` fact and + the value of SEED for repeatable randomness. (That is, each node will + get a different random rotation from this function, but a given node's + result will be the same every time unless its hostname changes.) Adding + a SEED can be useful if you need more than one unrelated rotation.", +) do |args| + + raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments given (#{args.size} for 1)") if args.empty? + + value = args.shift + require 'digest/md5' + + unless value.is_a?(Array) || value.is_a?(String) + 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 + + seed = Digest::MD5.hexdigest([lookupvar('::fqdn'), args].join(':')).hex + # deterministic_rand() was added in Puppet 3.2.0; reimplement if necessary + if Puppet::Util.respond_to?(:deterministic_rand) + offset = Puppet::Util.deterministic_rand(seed, elements).to_i + else + return offset = Random.new(seed).rand(elements) if defined?(Random) == 'constant' && Random.class == Class + + old_seed = srand(seed) + offset = rand(elements) + srand(old_seed) + end + offset.times do + result.push result.shift + end + + result = string ? result.join : result + + return result +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_uuid.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_uuid.rb new file mode 100644 index 0000000..5080e8e --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/fqdn_uuid.rb @@ -0,0 +1,86 @@ +require 'digest/sha1' +# +# fqdn_uuid.rb +# +module Puppet::Parser::Functions + newfunction(:fqdn_uuid, :type => :rvalue, :doc => <<-DOC) do |args| + Creates a UUID based on a given string, assumed to be the FQDN + + For example, to generate a UUID based on the FQDN of a system: + + Usage: + + $uuid = fqdn_uuid($::fqdn) + + The generated UUID will be the same for the given hostname + + The resulting UUID is returned on the form: + + 1d839dea-5e10-5243-88eb-e66815bd7d5c + + (u.e. without any curly braces.) + + The generated UUID is a version 5 UUID with the V5 DNS namespace: + + 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + + This only supports a the V5 SHA-1 hash, using the DNS namespace. + + Please consult http://www.ietf.org/rfc/rfc4122.txt for the details on + UUID generation and example implementation. + + No verification is present at the moment as whether the domain name given + is in fact a correct fully-qualified domain name. Therefore any arbitrary + string and/or alpha-numeric value can subside for a domain name. + DOC + + raise(ArgumentError, 'fqdn_uuid: No arguments given') if args.empty? + raise(ArgumentError, "fqdn_uuid: Too many arguments given (#{args.length})") unless args.length == 1 + fqdn = args[0] + + # Code lovingly taken from + # https://github.com/puppetlabs/marionette-collective/blob/master/lib/mcollective/ssl.rb + + # This is the UUID version 5 type DNS name space which is as follows: + # + # 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + # + uuid_name_space_dns = [0x6b, + 0xa7, + 0xb8, + 0x10, + 0x9d, + 0xad, + 0x11, + 0xd1, + 0x80, + 0xb4, + 0x00, + 0xc0, + 0x4f, + 0xd4, + 0x30, + 0xc8].map { |b| b.chr }.join + + sha1 = Digest::SHA1.new + sha1.update(uuid_name_space_dns) + sha1.update(fqdn) + + # first 16 bytes.. + bytes = sha1.digest[0, 16].bytes.to_a + + # version 5 adjustments + bytes[6] &= 0x0f + bytes[6] |= 0x50 + + # variant is DCE 1.1 + bytes[8] &= 0x3f + bytes[8] |= 0x80 + + bytes = [4, 2, 2, 2, 6].map do |i| + bytes.slice!(0, i).pack('C*').unpack('H*') + end + + bytes.join('-') + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb new file mode 100644 index 0000000..3a95b71 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb @@ -0,0 +1,18 @@ +# +# get_module_path.rb +# +module Puppet::Parser::Functions + newfunction(:get_module_path, :type => :rvalue, :doc => <<-DOC + Returns the absolute path of the specified module for the current + environment. + + Example: + $module_path = get_module_path('stdlib') + DOC + ) do |args| + raise(Puppet::ParseError, 'get_module_path(): Wrong number of arguments, expects one') unless args.size == 1 + module_path = Puppet::Module.find(args[0], compiler.environment.to_s) + raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}") unless module_path + module_path.path + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getparam.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getparam.rb new file mode 100644 index 0000000..d73650b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getparam.rb @@ -0,0 +1,36 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:getparam, + :type => :rvalue, + :doc => <<-'DOC' + 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 + DOC + ) do |vals| + reference, param = vals + raise(ArgumentError, 'Must specify a reference') unless reference + raise(ArgumentError, 'Must specify name of a parameter') unless param && param.instance_of?(String) + + return '' if param.empty? + + resource = findresource(reference.to_s) + if resource + return resource[param] unless resource[param].nil? + end + + return '' +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getvar.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getvar.rb new file mode 100644 index 0000000..f464467 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/getvar.rb @@ -0,0 +1,35 @@ +# +# getvar.rb +# +module Puppet::Parser::Functions + newfunction(:getvar, :type => :rvalue, :doc => <<-'DOC') 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 + DOC + + unless args.length == 1 + raise Puppet::ParseError, "getvar(): wrong number of arguments (#{args.length}; must be 1)" + end + + begin + result = nil + catch(:undefined_variable) do + result = lookupvar((args[0]).to_s) + end + + # avoid relying on incosistent behaviour around ruby return values from catch + result + rescue Puppet::ParseError # rubocop:disable Lint/HandleExceptions : Eat the exception if strict_variables = true is set + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/glob.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/glob.rb new file mode 100644 index 0000000..e9d35b2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/glob.rb @@ -0,0 +1,25 @@ +# +# glob.rb +# +module Puppet::Parser::Functions + newfunction(:glob, :type => :rvalue, :doc => <<-'DOC' + Returns an Array of file entries of a directory or an Array of directories. + Uses same patterns as Dir#glob + DOC + ) do |arguments| + + unless arguments.size == 1 + raise(Puppet::ParseError, 'glob(): Wrong number of arguments given ' \ + "(#{arguments.size} for 1)") + end + + pattern = arguments[0] + + unless pattern.is_a?(String) || pattern.is_a?(Array) + raise(Puppet::ParseError, 'glob(): Requires either array or string ' \ + 'to work') + end + + Dir.glob(pattern) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/grep.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/grep.rb new file mode 100644 index 0000000..030c14a --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/grep.rb @@ -0,0 +1,30 @@ +# +# grep.rb +# +module Puppet::Parser::Functions + newfunction(:grep, :type => :rvalue, :doc => <<-DOC + 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'] + DOC + ) do |arguments| + + if arguments.size != 2 + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb new file mode 100644 index 0000000..44005d0 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb @@ -0,0 +1,69 @@ +# +# has_interface_with +# +module Puppet::Parser::Functions + newfunction(:has_interface_with, :type => :rvalue, :doc => <<-DOC + 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 + DOC + ) do |args| + + raise(Puppet::ParseError, "has_interface_with(): Wrong number of arguments given (#{args.size} for 1 or 2)") if args.empty? || 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.nil? + + interfaces = interfaces.split(',') + + if args.size == 1 + return interfaces.member?(args[0]) + end + + kind, value = args + + # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable + # https://tickets.puppetlabs.com/browse/PUP-3597 + factval = nil + begin + catch :undefined_variable do + factval = lookupvar(kind) + end + rescue Puppet::ParseError # rubocop:disable Lint/HandleExceptions : Eat the exception if strict_variables = true is set + end + if factval == value + return true + end + + result = false + interfaces.each do |iface| + iface.downcase! + factval = nil + begin + # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable + # https://tickets.puppetlabs.com/browse/PUP-3597 + catch :undefined_variable do + factval = lookupvar("#{kind}_#{iface}") + end + rescue Puppet::ParseError # rubocop:disable Lint/HandleExceptions : Eat the exception if strict_variables = true is set + end + if value == factval + result = true + break + end + end + + result + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb new file mode 100644 index 0000000..5f14ee2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb @@ -0,0 +1,22 @@ +# +# has_ip_address +# +module Puppet::Parser::Functions + newfunction(:has_ip_address, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb new file mode 100644 index 0000000..65f2789 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb @@ -0,0 +1,22 @@ +# +# has_ip_network +# +module Puppet::Parser::Functions + newfunction(:has_ip_network, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_key.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_key.rb new file mode 100644 index 0000000..53b8c74 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/has_key.rb @@ -0,0 +1,28 @@ +# +# has_key.rb +# +module Puppet::Parser::Functions + newfunction(:has_key, :type => :rvalue, :doc => <<-'DOC') 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') + } + + DOC + + 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].key?(args[1]) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/hash.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/hash.rb new file mode 100644 index 0000000..f6644db --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/hash.rb @@ -0,0 +1,38 @@ +# +# hash.rb +# +module Puppet::Parser::Functions + newfunction(:hash, :type => :rvalue, :doc => <<-DOC + This function converts an array into a hash. + + *Examples:* + + hash(['a',1,'b',2,'c',3]) + + Would return: {'a'=>1,'b'=>2,'c'=>3} + DOC + ) do |arguments| + + raise(Puppet::ParseError, "hash(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + 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 StandardError + raise(Puppet::ParseError, 'hash(): Unable to compute hash from array given') + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/intersection.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/intersection.rb new file mode 100644 index 0000000..0c16722 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/intersection.rb @@ -0,0 +1,31 @@ +# +# intersection.rb +# +module Puppet::Parser::Functions + newfunction(:intersection, :type => :rvalue, :doc => <<-DOC + This function returns an array of the intersection of two. + + *Examples:* + + intersection(["a","b","c"],["b","c","d"]) # returns ["b","c"] + intersection(["a","b","c"],[1,2,3,4]) # returns [] (true, when evaluated as a Boolean) + DOC + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "intersection(): Wrong number of arguments given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'intersection(): Requires 2 arrays') + end + + result = first & second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_absolute_path.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_absolute_path.rb new file mode 100644 index 0000000..06e9465 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_absolute_path.rb @@ -0,0 +1,54 @@ +# +# is_absolute_path.rb +# +module Puppet::Parser::Functions + newfunction(:is_absolute_path, :type => :rvalue, :arity => 1, :doc => <<-'DOC') do |args| + Returns boolean true if the string represents an absolute path in the filesystem. This function works + for windows and unix style paths. + + The following values will return true: + + $my_path = 'C:/Program Files (x86)/Puppet Labs/Puppet' + is_absolute_path($my_path) + $my_path2 = '/var/lib/puppet' + is_absolute_path($my_path2) + $my_path3 = ['C:/Program Files (x86)/Puppet Labs/Puppet'] + is_absolute_path($my_path3) + $my_path4 = ['/var/lib/puppet'] + is_absolute_path($my_path4) + + The following values will return false: + + is_absolute_path(true) + is_absolute_path('../var/lib/puppet') + is_absolute_path('var/lib/puppet') + $undefined = undef + is_absolute_path($undefined) + + DOC + function_deprecation([:is_absolute_path, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Absolute_path. There is further documentation for validate_legacy function in the README.']) + require 'puppet/util' + + path = args[0] + # 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?) + value = (Puppet::Util.absolute_path?(path, :posix) || Puppet::Util.absolute_path?(path, :windows)) + 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{^/}, + } + value = !!(path =~ regexes[:posix]) || !!(path =~ regexes[:windows]) # rubocop:disable Style/DoubleNegation : No alternative known + end + value + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_array.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_array.rb new file mode 100644 index 0000000..620f4f7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_array.rb @@ -0,0 +1,21 @@ +# +# is_array.rb +# +module Puppet::Parser::Functions + newfunction(:is_array, :type => :rvalue, :doc => <<-DOC + Returns true if the variable passed to this function is an array. + DOC + ) do |arguments| + + function_deprecation([:is_array, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Array. There is further documentation for validate_legacy function in the README.']) + + raise(Puppet::ParseError, "is_array(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + type = arguments[0] + + result = type.is_a?(Array) + + return result + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_bool.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_bool.rb new file mode 100644 index 0000000..d0e0026 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_bool.rb @@ -0,0 +1,21 @@ +# +# is_bool.rb +# +module Puppet::Parser::Functions + newfunction(:is_bool, :type => :rvalue, :doc => <<-DOC + Returns true if the variable passed to this function is a boolean. + DOC + ) do |arguments| + + function_deprecation([:is_bool, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Bool. There is further documentation for validate_legacy function in the README.']) + + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb new file mode 100644 index 0000000..d80689a --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb @@ -0,0 +1,51 @@ +# +# is_domain_name.rb +# +module Puppet::Parser::Functions + newfunction(:is_domain_name, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a syntactically correct domain name. + DOC + ) do |arguments| + + if arguments.size != 1 + raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments given #{arguments.size} for 1") + end + + # Only allow string types + return false unless arguments[0].is_a?(String) + + domain = arguments[0].dup + + # Limits (rfc1035, 3.1) + domain_max_length = 255 + label_min_length = 1 + label_max_length = 63 + + # 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 + + # The top level domain must be alphabetic if there are multiple labels. + # See rfc1123, 2.1 + return false if domain.include?('.') && !%r{\.[A-Za-z]+$}.match(domain) + + # 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 %r{^[a-z\d-]+$}i =~ label + end + return vlabels == labels + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_email_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_email_address.rb new file mode 100644 index 0000000..f656468 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_email_address.rb @@ -0,0 +1,19 @@ +# +# is_email_address.rb +# +module Puppet::Parser::Functions + newfunction(:is_email_address, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a valid email address. + DOC + ) do |arguments| + if arguments.size != 1 + raise(Puppet::ParseError, "is_email_address(): Wrong number of arguments given #{arguments.size} for 1") + end + + # Taken from http://emailregex.com/ (simpler regex) + valid_email_regex = %r{\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z} + return (arguments[0] =~ valid_email_regex) == 0 # rubocop:disable Style/NumericPredicate : Changing to '.zero?' breaks the code + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_float.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_float.rb new file mode 100644 index 0000000..89994d2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_float.rb @@ -0,0 +1,27 @@ +# +# is_float.rb +# +module Puppet::Parser::Functions + newfunction(:is_float, :type => :rvalue, :doc => <<-DOC + Returns true if the variable passed to this function is a float. + DOC + ) do |arguments| + + function_deprecation([:is_float, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Float. There is further documentation for validate_legacy function in the README.']) + + if arguments.size != 1 + 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) || value.is_a?(String) + + return false if value != value.to_f.to_s && !value.is_a?(Float) + return true + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb new file mode 100644 index 0000000..e02aa53 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb @@ -0,0 +1,24 @@ +# +# is_function_available.rb +# +module Puppet::Parser::Functions + newfunction(:is_function_available, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + if arguments.size != 1 + 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) && !function.empty? + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_hash.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_hash.rb new file mode 100644 index 0000000..dc03653 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_hash.rb @@ -0,0 +1,20 @@ +# +# is_hash.rb +# +module Puppet::Parser::Functions + newfunction(:is_hash, :type => :rvalue, :doc => <<-DOC + Returns true if the variable passed to this function is a hash. + DOC + ) 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_integer.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_integer.rb new file mode 100644 index 0000000..7444cac --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_integer.rb @@ -0,0 +1,43 @@ +# +# is_integer.rb +# +module Puppet::Parser::Functions + newfunction(:is_integer, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) do |arguments| + + function_deprecation([:is_integer, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Integer. There is further documentation for validate_legacy function in the README.']) + + if arguments.size != 1 + 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)$} + + return true if value.is_a?(Integer) || (value.is_a?(String) && value.match(numeric)) + return false + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb new file mode 100644 index 0000000..6ce993a --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb @@ -0,0 +1,30 @@ +# +# is_ip_address.rb +# +module Puppet::Parser::Functions + newfunction(:is_ip_address, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a valid IP address. + DOC + ) do |arguments| + + require 'ipaddr' + + function_deprecation([:is_ip_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ip_address. There is further documentation for validate_legacy function in the README.']) + + if arguments.size != 1 + 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 + + return true if ip.ipv4? || ip.ipv6? + return false + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv4_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv4_address.rb new file mode 100644 index 0000000..7f2241b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv4_address.rb @@ -0,0 +1,29 @@ +# +# is_ipv4_address.rb +# +module Puppet::Parser::Functions + newfunction(:is_ipv4_address, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a valid IPv4 address. + DOC + ) do |arguments| + + require 'ipaddr' + + function_deprecation([:is_ipv4_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv4. There is further documentation for validate_legacy function in the README.']) + + if arguments.size != 1 + raise(Puppet::ParseError, "is_ipv4_address(): Wrong number of arguments given #{arguments.size} for 1") + end + + begin + ip = IPAddr.new(arguments[0]) + rescue ArgumentError + return false + end + + return ip.ipv4? + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv6_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv6_address.rb new file mode 100644 index 0000000..35be026 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_ipv6_address.rb @@ -0,0 +1,29 @@ +# +# is_ipv6_address.rb +# +module Puppet::Parser::Functions + newfunction(:is_ipv6_address, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a valid IPv6 address. + DOC + ) do |arguments| + + function_deprecation([:is_ipv6_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv6. There is further documentation for validate_legacy function in the README.']) + + require 'ipaddr' + + if arguments.size != 1 + raise(Puppet::ParseError, "is_ipv6_address(): Wrong number of arguments given #{arguments.size} for 1") + end + + begin + ip = IPAddr.new(arguments[0]) + rescue ArgumentError + return false + end + + return ip.ipv6? + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb new file mode 100644 index 0000000..83a5ba2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb @@ -0,0 +1,21 @@ +# +# is_mac_address.rb +# +module Puppet::Parser::Functions + newfunction(:is_mac_address, :type => :rvalue, :doc => <<-DOC + Returns true if the string passed to this function is a valid mac address. + DOC + ) do |arguments| + + if arguments.size != 1 + raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments given #{arguments.size} for 1") + end + + mac = arguments[0] + + return true if %r{^[a-f0-9]{1,2}(:[a-f0-9]{1,2}){5}$}i =~ mac + return false + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb new file mode 100644 index 0000000..e127705 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb @@ -0,0 +1,74 @@ +# +# is_numeric.rb +# +module Puppet::Parser::Functions + newfunction(:is_numeric, :type => :rvalue, :doc => <<-DOC + 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 + DOC + ) do |arguments| + + function_deprecation([:is_numeric, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Numeric. There is further documentation for validate_legacy function in the README.']) + + if arguments.size != 1 + 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) || (value.is_a?(String) && + value.match(numeric) # or + # value.match(numeric_hex) or + # value.match(numeric_oct) + ) + return true + else + return false + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_string.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_string.rb new file mode 100644 index 0000000..f7b1b14 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/is_string.rb @@ -0,0 +1,28 @@ +# +# is_string.rb +# +module Puppet::Parser::Functions + newfunction(:is_string, :type => :rvalue, :doc => <<-DOC + Returns true if the variable passed to this function is a string. + DOC + ) do |arguments| + + function_deprecation([:is_string, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::String. There is further documentation for validate_legacy function in the README.']) + + raise(Puppet::ParseError, "is_string(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + type = arguments[0] + + # when called through the v4 API shim, undef gets translated to nil + result = type.is_a?(String) || type.nil? + + if result && (type == type.to_f.to_s || type == type.to_i.to_s) + return false + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join.rb new file mode 100644 index 0000000..bcb97b7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join.rb @@ -0,0 +1,39 @@ +# +# join.rb +# +module Puppet::Parser::Functions + newfunction(:join, :type => :rvalue, :doc => <<-DOC + This function joins an array into a string using a separator. + + *Examples:* + + join(['a','b','c'], ",") + + Would result in: "a,b,c" + DOC + ) 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.empty? + + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb new file mode 100644 index 0000000..3232fa8 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb @@ -0,0 +1,53 @@ +# +# join.rb +# +module Puppet::Parser::Functions + newfunction(:join_keys_to_values, :type => :rvalue, :doc => <<-DOC + This function joins each key of a hash to that key's corresponding value with a + separator. Keys are cast to strings. If values are arrays, multiple keys + are added for each element. 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"] + + join_keys_to_values({'a'=>1,'b'=>[2,3]}, " is ") + + Would result in: ["a is 1","b is 2","b is 3"] + DOC + ) 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] + unless 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] + unless 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 { |k, v| + if v.is_a?(Array) + v.map { |va| String(k) + separator + String(va) } + elsif String(v) == 'undef' + String(k) + else + String(k) + separator + String(v) + end + }.flatten + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/keys.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/keys.rb new file mode 100644 index 0000000..0ecd48f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/keys.rb @@ -0,0 +1,24 @@ +# +# keys.rb +# +module Puppet::Parser::Functions + newfunction(:keys, :type => :rvalue, :doc => <<-DOC + Returns the keys of a hash as an array. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "keys(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/load_module_metadata.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/load_module_metadata.rb new file mode 100644 index 0000000..f9a39de --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/load_module_metadata.rb @@ -0,0 +1,25 @@ +# +# load_module_metadata.rb +# +module Puppet::Parser::Functions + newfunction(:load_module_metadata, :type => :rvalue, :doc => <<-DOC + This function loads the metadata of a given module. + DOC + ) do |args| + raise(Puppet::ParseError, 'load_module_metadata(): Wrong number of arguments, expects one or two') unless [1, 2].include?(args.size) + mod = args[0] + allow_empty_metadata = args[1] + module_path = function_get_module_path([mod]) + metadata_json = File.join(module_path, 'metadata.json') + + metadata_exists = File.exists?(metadata_json) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code + if metadata_exists + metadata = PSON.load(File.read(metadata_json)) + else + metadata = {} + raise(Puppet::ParseError, "load_module_metadata(): No metadata.json file for module #{mod}") unless allow_empty_metadata + end + + return metadata + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadjson.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadjson.rb new file mode 100644 index 0000000..9a1d54f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadjson.rb @@ -0,0 +1,32 @@ +# +# loadjson.rb +# +module Puppet::Parser::Functions + newfunction(:loadjson, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args| + Load a JSON file containing an array, string, or hash, and return the data + in the corresponding native data type. + The second parameter is the default value. It will be returned if the file + was not found or could not be parsed. + + For example: + + $myhash = loadjson('/etc/puppet/data/myhash.json') + $myhash = loadjson('no-file.json', {'default' => 'value'}) + DOC + + raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1 + + if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code + begin + content = File.read(args[0]) + PSON.load(content) || args[1] + rescue StandardError => e + raise e unless args[1] + args[1] + end + else + warning("Can't load '#{args[0]}' File does not exist!") + args[1] + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb new file mode 100644 index 0000000..a8c9e62 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb @@ -0,0 +1,32 @@ +# +# loadyaml.rb +# +module Puppet::Parser::Functions + newfunction(:loadyaml, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args| + Load a YAML file containing an array, string, or hash, and return the data + in the corresponding native data type. + The second parameter is the default value. It will be returned if the file + was not found or could not be parsed. + + For example: + + $myhash = loadyaml('/etc/puppet/data/myhash.yaml') + $myhash = loadyaml('no-file.yaml', {'default' => 'value'}) + DOC + + raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1 + require 'yaml' + + if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code + begin + YAML.load_file(args[0]) || args[1] + rescue StandardError => e + raise e unless args[1] + args[1] + end + else + warning("Can't load '#{args[0]}' File does not exist!") + args[1] + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/lstrip.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/lstrip.rb new file mode 100644 index 0000000..f5b9a58 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/lstrip.rb @@ -0,0 +1,29 @@ +# +# lstrip.rb +# +module Puppet::Parser::Functions + newfunction(:lstrip, :type => :rvalue, :doc => <<-DOC + Strips leading spaces to the left of a string. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "lstrip(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'lstrip(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.lstrip : i } + else + value.lstrip + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/max.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/max.rb new file mode 100644 index 0000000..21c5245 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/max.rb @@ -0,0 +1,23 @@ +# +# max.rb +# +module Puppet::Parser::Functions + newfunction(:max, :type => :rvalue, :doc => <<-DOC + Returns the highest value of all arguments. + Requires at least one argument. + DOC + ) do |args| + + raise(Puppet::ParseError, 'max(): Wrong number of arguments need at least one') if args.empty? + + # 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 =~ %r{\A-?\d+(.\d+)?\z} && b.to_s =~ %r{\A-?\d+(.\d+)?\z} + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/member.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/member.rb new file mode 100644 index 0000000..9261080 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/member.rb @@ -0,0 +1,57 @@ +# TODO(Krzysztof Wilczynski): We need to add support for regular expression ... +# TODO(Krzysztof Wilczynski): Support for strings and hashes too ... +# +# member.rb +# +module Puppet::Parser::Functions + newfunction(:member, :type => :rvalue, :doc => <<-DOC + This function determines if a variable is a member of an array. + The variable can be a string, fixnum, or array. + + *Examples:* + + member(['a','b'], 'b') + + Would return: true + + member(['a', 'b', 'c'], ['a', 'b']) + + would return: true + + member(['a','b'], 'c') + + Would return: false + + member(['a', 'b', 'c'], ['d', 'b']) + + would return: false + DOC + ) 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 + + unless arguments[1].is_a?(String) || arguments[1].is_a?(Integer) || arguments[1].is_a?(Array) + raise(Puppet::ParseError, 'member(): Item to search for must be a string, fixnum, or array') + end + + item = if arguments[1].is_a?(String) || arguments[1].is_a?(Integer) + [arguments[1]] + else + arguments[1] + end + + raise(Puppet::ParseError, 'member(): You must provide item to search for within array given') if item.respond_to?('empty?') && item.empty? + + result = (item - array).empty? + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/merge.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/merge.rb new file mode 100644 index 0000000..25ebc79 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/merge.rb @@ -0,0 +1,37 @@ +# +# merge.rb +# +module Puppet::Parser::Functions + newfunction(:merge, :type => :rvalue, :doc => <<-'DOC') 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." + + DOC + + 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 = {} + # Merge into the accumulator hash + args.each do |arg| + next if arg.is_a?(String) && 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/min.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/min.rb new file mode 100644 index 0000000..985ec56 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/min.rb @@ -0,0 +1,23 @@ +# +# min.rb +# +module Puppet::Parser::Functions + newfunction(:min, :type => :rvalue, :doc => <<-DOC + Returns the lowest value of all arguments. + Requires at least one argument. + DOC + ) do |args| + + raise(Puppet::ParseError, 'min(): Wrong number of arguments need at least one') if args.empty? + + # 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 =~ %r{\A^-?\d+(.\d+)?\z} && b.to_s =~ %r{\A-?\d+(.\d+)?\z} + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/num2bool.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/num2bool.rb new file mode 100644 index 0000000..0957c56 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/num2bool.rb @@ -0,0 +1,41 @@ +# +# num2bool.rb +# +module Puppet::Parser::Functions + newfunction(:num2bool, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) 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 # rubocop:disable Lint/EmptyWhen : Required for the module to work + # 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parsejson.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parsejson.rb new file mode 100644 index 0000000..4cc43e6 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parsejson.rb @@ -0,0 +1,24 @@ +# +# parsejson.rb +# +module Puppet::Parser::Functions + newfunction(:parsejson, :type => :rvalue, :doc => <<-DOC + This function accepts JSON as a string and converts it into the correct + Puppet structure. + + The optional second argument can be used to pass a default value that will + be returned if the parsing of YAML string have failed. + DOC + ) do |arguments| + raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless arguments.length >= 1 + + begin + PSON.load(arguments[0]) || arguments[1] + rescue StandardError => e + raise e unless arguments[1] + arguments[1] + end + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb new file mode 100644 index 0000000..7f857ca --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb @@ -0,0 +1,28 @@ +# +# parseyaml.rb +# +module Puppet::Parser::Functions + newfunction(:parseyaml, :type => :rvalue, :doc => <<-DOC + This function accepts YAML as a string and converts it into the correct + Puppet structure. + + The optional second argument can be used to pass a default value that will + be returned if the parsing of YAML string have failed. + DOC + ) do |arguments| + raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless arguments.length >= 1 + require 'yaml' + + begin + YAML.load(arguments[0]) || arguments[1] # rubocop:disable Security/YAMLLoad : using YAML.safe_load causes the code to break + # in ruby 1.9.3 Psych::SyntaxError is a RuntimeException + # this still needs to catch that and work also on rubies that + # do not have Psych available. + rescue StandardError, Psych::SyntaxError => e # rubocop:disable Lint/ShadowedException : See above + raise e unless arguments[1] + arguments[1] + end + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick.rb new file mode 100644 index 0000000..300e164 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick.rb @@ -0,0 +1,27 @@ +# +# pick.rb +# +module Puppet::Parser::Functions + newfunction(:pick, :type => :rvalue, :doc => <<-DOC + 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. +DOC + ) do |args| + args = args.compact + args.delete(:undef) + args.delete(:undefined) + args.delete('') + raise Puppet::ParseError, 'pick(): must receive at least one non empty value' if args[0].to_s.empty? + return args[0] + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick_default.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick_default.rb new file mode 100644 index 0000000..29aaef2 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pick_default.rb @@ -0,0 +1,36 @@ +# +# pick_default.rb +# +module Puppet::Parser::Functions + newfunction(:pick_default, :type => :rvalue, :doc => <<-DOC + 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. +DOC + ) do |args| + raise '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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/prefix.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/prefix.rb new file mode 100644 index 0000000..7490a18 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/prefix.rb @@ -0,0 +1,50 @@ +# +# prefix.rb +# +module Puppet::Parser::Functions + newfunction(:prefix, :type => :rvalue, :doc => <<-DOC + This function applies a prefix to all elements in an array or a hash. + + *Examples:* + + prefix(['a','b','c'], 'p') + + Will return: ['pa','pb','pc'] + DOC + ) 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.empty? + + enumerable = arguments[0] + + unless enumerable.is_a?(Array) || enumerable.is_a?(Hash) + raise Puppet::ParseError, "prefix(): expected first argument to be an Array or a Hash, got #{enumerable.inspect}" + end + + prefix = arguments[1] if arguments[1] + + if prefix + unless prefix.is_a?(String) + raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{prefix.inspect}" + end + end + + result = if enumerable.is_a?(Array) + # Turn everything into string same as join would do ... + enumerable.map do |i| + i = i.to_s + prefix ? prefix + i : i + end + else + Hash[enumerable.map do |k, v| + k = k.to_s + [prefix ? prefix + k : k, v] + end] + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/private.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/private.rb new file mode 100644 index 0000000..5e0b7c5 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/private.rb @@ -0,0 +1,16 @@ +# +# private.rb +# +module Puppet::Parser::Functions + newfunction(:private, :doc => <<-'DOC' + DEPRECATED: Sets the current class or definition as private. + Calling the class or definition from outside the current module will fail. + DOC + ) do |args| + warning("private() DEPRECATED: This function will cease to function on Puppet 4; please use assert_private() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.") # rubocop:disable Metrics/LineLength : Cannot shorten this line + unless Puppet::Parser::Functions.autoloader.loaded?(:assert_private) + Puppet::Parser::Functions.autoloader.load(:assert_private) + end + function_assert_private([(args[0] unless args.empty?)]) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pry.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pry.rb new file mode 100644 index 0000000..17b3bc7 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pry.rb @@ -0,0 +1,29 @@ +# +# pry.rb +# +module Puppet::Parser::Functions + newfunction(:pry, :type => :statement, :doc => <<-DOC + This function invokes a pry debugging session in the current scope object. This is useful for debugging manifest code at specific points during a compilation. + + *Examples:* + + pry() + DOC + ) do |arguments| + begin + require 'pry' + rescue LoadError + raise(Puppet::Error, "pry(): Requires the 'pry' rubygem to use, but it was not found") + end + # + ## Run `catalog` to see the contents currently compiling catalog + ## Run `cd catalog` and `ls` to see catalog methods and instance variables + ## Run `@resource_table` to see the current catalog resource table + # + if $stdout.isatty + binding.pry # rubocop:disable Lint/Debugger + else + Puppet.warning 'pry(): cowardly refusing to start the debugger on a daemonized master' + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pw_hash.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pw_hash.rb new file mode 100644 index 0000000..eaf1d74 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/pw_hash.rb @@ -0,0 +1,62 @@ +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +Puppet::Parser::Functions.newfunction( + :pw_hash, + :type => :rvalue, + :arity => 3, + :doc => "Hashes a password using the crypt function. Provides a hash + usable on most POSIX systems. + + The first argument to this function is the password to hash. If it is + undef or an empty string, this function returns undef. + + The second argument to this function is which type of hash to use. It + will be converted into the appropriate crypt(3) hash specifier. Valid + hash types are: + + |Hash type |Specifier| + |---------------------|---------| + |MD5 |1 | + |SHA-256 |5 | + |SHA-512 (recommended)|6 | + + The third argument to this function is the salt to use. + + Note: this uses the Puppet Master's implementation of crypt(3). If your + environment contains several different operating systems, ensure that they + are compatible before using this function.", +) do |args| + raise ArgumentError, "pw_hash(): wrong number of arguments (#{args.size} for 3)" if args.size != 3 + args.map! do |arg| + if (defined? Puppet::Pops::Types::PSensitiveType::Sensitive) && (arg.is_a? Puppet::Pops::Types::PSensitiveType::Sensitive) + arg.unwrap + else + arg + end + end + raise ArgumentError, 'pw_hash(): first argument must be a string' unless args[0].is_a?(String) || args[0].nil? + raise ArgumentError, 'pw_hash(): second argument must be a string' unless args[1].is_a? String + hashes = { 'md5' => '1', + 'sha-256' => '5', + 'sha-512' => '6' } + hash_type = hashes[args[1].downcase] + raise ArgumentError, "pw_hash(): #{args[1]} is not a valid hash type" if hash_type.nil? + raise ArgumentError, 'pw_hash(): third argument must be a string' unless args[2].is_a? String + raise ArgumentError, 'pw_hash(): third argument must not be empty' if args[2].empty? + raise ArgumentError, 'pw_hash(): characters in salt must be in the set [a-zA-Z0-9./]' unless args[2] =~ %r{\A[a-zA-Z0-9./]+\z} + + password = args[0] + return nil if password.nil? || password.empty? + + salt = "$#{hash_type}$#{args[2]}" + + # handle weak implementations of String#crypt + if 'test'.crypt('$1$1') != '$1$1$Bp8CU9Oujr9SSEw53WV6G.' + # JRuby < 1.7.17 + # MS Windows and other systems that don't support enhanced salts + raise Puppet::ParseError, 'system does not support enhanced salts' unless RUBY_PLATFORM == 'java' + # puppetserver bundles Apache Commons Codec + org.apache.commons.codec.digest.Crypt.crypt(password.to_java_bytes, salt) + else + password.crypt(salt) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/range.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/range.rb new file mode 100644 index 0000000..3e5cc44 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/range.rb @@ -0,0 +1,84 @@ +# +# range.rb +# +# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ... +module Puppet::Parser::Functions + newfunction(:range, :type => :rvalue, :doc => <<-DOC + 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"] + NB Be explicit in including trailing zeros. Otherwise the underlying ruby function will fail. + + 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] + DOC + ) do |arguments| + + raise(Puppet::ParseError, 'range(): Wrong number of arguments given (0 for 1)') if arguments.empty? + + if arguments.size > 1 + start = arguments[0] + stop = arguments[1] + step = arguments[2].nil? ? 1 : arguments[2].to_i.abs + + type = '..' # Use the simplest type of Range available in Ruby + + else # arguments.size == 1 + value = arguments[0] + + m = value.match(%r{^(\w+)(\.\.\.?|\-)(\w+)$}) + if m + start = m[1] + stop = m[3] + + type = m[2] + step = 1 + elsif value =~ %r{^.+$} + raise(Puppet::ParseError, "range(): Unable to compute range from the value: #{value}") + else + raise(Puppet::ParseError, "range(): Unknown range format: #{value}") + end + end + + # If we were given an integer, ensure we work with one + if start.to_s =~ %r{^\d+$} + start = start.to_i + stop = stop.to_i + else + start = start.to_s + stop = stop.to_s + end + + range = case type + when %r{^(..|-)$} then (start..stop) + when '...' then (start...stop) # Exclusive of last element + end + + result = range.step(step).to_a + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/regexpescape.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/regexpescape.rb new file mode 100644 index 0000000..647d865 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/regexpescape.rb @@ -0,0 +1,29 @@ +# +# regexpescape.rb +# +module Puppet::Parser::Functions + newfunction(:regexpescape, :type => :rvalue, :doc => <<-DOC + Regexp escape a string or array of strings. + Requires either a single string or an array as an input. + DOC + ) do |arguments| # rubocop:disable Layout/ClosingParenthesisIndentation + raise(Puppet::ParseError, "regexpescape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'regexpescape(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? Regexp.escape(i) : i } + else + Regexp.escape(value) + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reject.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reject.rb new file mode 100644 index 0000000..be2f017 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reject.rb @@ -0,0 +1,30 @@ +# +# reject.rb +# +module Puppet::Parser::Functions + newfunction(:reject, :type => :rvalue, :doc => <<-DOC) 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'] +DOC + + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reverse.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reverse.rb new file mode 100644 index 0000000..ea911ec --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/reverse.rb @@ -0,0 +1,24 @@ +# +# reverse.rb +# +module Puppet::Parser::Functions + newfunction(:reverse, :type => :rvalue, :doc => <<-DOC + Reverses the order of a string or array. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "reverse(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/round.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/round.rb new file mode 100644 index 0000000..b4f2c2b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/round.rb @@ -0,0 +1,32 @@ +# +# round.rb +# +module Puppet::Parser::Functions + newfunction(:round, :type => :rvalue, :doc => <<-DOC + Rounds a number to the nearest integer + + *Examples:* + + round(2.9) + + returns: 3 + + round(2.4) + + returns: 2 + + DOC + ) do |args| + + raise Puppet::ParseError, "round(): Wrong number of arguments given #{args.size} for 1" if args.size != 1 + raise Puppet::ParseError, "round(): Expected a Numeric, got #{args[0].class}" unless args[0].is_a? Numeric + + value = args[0] + + if value >= 0 + Integer(value + 0.5) + else + Integer(value - 0.5) + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/rstrip.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/rstrip.rb new file mode 100644 index 0000000..3e04b27 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/rstrip.rb @@ -0,0 +1,28 @@ +# +# rstrip.rb +# +module Puppet::Parser::Functions + newfunction(:rstrip, :type => :rvalue, :doc => <<-DOC + Strips leading spaces to the right of the string. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "rstrip(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'rstrip(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + value.map { |i| i.is_a?(String) ? i.rstrip : i } + else + value.rstrip + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/seeded_rand.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/seeded_rand.rb new file mode 100644 index 0000000..0120b87 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/seeded_rand.rb @@ -0,0 +1,24 @@ +# +# seeded_rand.rb +# +Puppet::Parser::Functions.newfunction( + :seeded_rand, + :arity => 2, + :type => :rvalue, + :doc => <<-DOC + Usage: `seeded_rand(MAX, SEED)`. MAX must be a positive integer; SEED is any string. + + Generates a random whole number greater than or equal to 0 and less + than MAX, using the value of SEED for repeatable randomness. If SEED + starts with "$fqdn:", this is behaves the same as `fqdn_rand`. +DOC +) do |args| + require 'digest/md5' + + raise(ArgumentError, 'seeded_rand(): first argument must be a positive integer') unless function_is_integer([args[0]]) && args[0].to_i > 0 + raise(ArgumentError, 'seeded_rand(): second argument must be a string') unless args[1].is_a? String + + max = args[0].to_i + seed = Digest::MD5.hexdigest(args[1]).hex + Puppet::Util.deterministic_rand(seed, max) +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_escape.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_escape.rb new file mode 100644 index 0000000..96fea20 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_escape.rb @@ -0,0 +1,27 @@ +require 'shellwords' +# +# shell_escape.rb +# +module Puppet::Parser::Functions + newfunction(:shell_escape, :type => :rvalue, :doc => <<-DOC + Escapes a string so that it can be safely used in a Bourne shell command line. + + Note that the resulting string should be used unquoted and is not intended for use in double quotes nor in single + quotes. + + This function behaves the same as ruby's Shellwords.shellescape() function. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "shell_escape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + # explicit conversion to string is required for ruby 1.9 + string = arguments[0].to_s + + result = Shellwords.shellescape(string) + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_join.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_join.rb new file mode 100644 index 0000000..0a037c1 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_join.rb @@ -0,0 +1,29 @@ + +require 'shellwords' +# +# shell_join.rb +# +module Puppet::Parser::Functions + newfunction(:shell_join, :type => :rvalue, :doc => <<-DOC + Builds a command line string from the given array of strings. Each array item is escaped for Bourne shell. All items are + then joined together, with a single space in between. + + This function behaves the same as ruby's Shellwords.shelljoin() function + DOC + ) do |arguments| + + raise(Puppet::ParseError, "shell_join(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + array = arguments[0] + + raise Puppet::ParseError, "First argument is not an Array: #{array.inspect}" unless array.is_a?(Array) + + # explicit conversion to string is required for ruby 1.9 + array = array.map { |item| item.to_s } + result = Shellwords.shelljoin(array) + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_split.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_split.rb new file mode 100644 index 0000000..9dcf958 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shell_split.rb @@ -0,0 +1,23 @@ +require 'shellwords' +# +# shell_split.rb +# +module Puppet::Parser::Functions + newfunction(:shell_split, :type => :rvalue, :doc => <<-DOC + Splits a string into an array of tokens in the same way the Bourne shell does. + + This function behaves the same as ruby's Shellwords.shellsplit() function + DOC + ) do |arguments| + + raise(Puppet::ParseError, "shell_split(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + string = arguments[0].to_s + + result = Shellwords.shellsplit(string) + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shuffle.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shuffle.rb new file mode 100644 index 0000000..5e6d93b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/shuffle.rb @@ -0,0 +1,42 @@ +# +# shuffle.rb +# +module Puppet::Parser::Functions + newfunction(:shuffle, :type => :rvalue, :doc => <<-DOC + Randomizes the order of a string or array elements. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "shuffle(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + 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 Fisher–Yates 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/size.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/size.rb new file mode 100644 index 0000000..27f9614 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/size.rb @@ -0,0 +1,44 @@ +# +# size.rb +# +module Puppet::Parser::Functions + newfunction(:size, :type => :rvalue, :doc => <<-DOC + Returns the number of elements in a string, an array or a hash + DOC + ) do |arguments| + + raise(Puppet::ParseError, "size(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + item = arguments[0] + + function_deprecation([:size, 'This method is going to be deprecated, please use the stdlib length function.']) + + 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, array or hash to work with') + rescue ArgumentError + result = item.size + end + + elsif item.is_a?(Array) || item.is_a?(Hash) + result = item.size + else + raise(Puppet::ParseError, 'size(): Unknown type given') + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/sort.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/sort.rb new file mode 100644 index 0000000..f0b4a14 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/sort.rb @@ -0,0 +1,25 @@ +# +# sort.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:sort, :type => :rvalue, :doc => <<-DOC + Sorts strings and arrays lexically. + DOC + ) do |arguments| + + if arguments.size != 1 + raise(Puppet::ParseError, "sort(): Wrong number of arguments given #{arguments.size} for 1") + end + + value = arguments[0] + + if value.is_a?(Array) + value.sort + elsif value.is_a?(String) + value.split('').sort.join('') + end + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/squeeze.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/squeeze.rb new file mode 100644 index 0000000..eaa1404 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/squeeze.rb @@ -0,0 +1,31 @@ +# +# squeeze.rb +# +module Puppet::Parser::Functions + newfunction(:squeeze, :type => :rvalue, :doc => <<-DOC + Returns a new string where runs of the same character that occur in this set are replaced by a single character. + DOC + ) do |arguments| + + if (arguments.size != 2) && (arguments.size != 1) + 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) + if squeezeval + item.map { |i| i.squeeze(squeezeval) } + else + item.map { |i| i.squeeze } + end + elsif squeezeval + item.squeeze(squeezeval) + else + item.squeeze + end + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2bool.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2bool.rb new file mode 100644 index 0000000..95c260c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2bool.rb @@ -0,0 +1,43 @@ +# +# str2bool.rb +# +module Puppet::Parser::Functions + newfunction(:str2bool, :type => :rvalue, :doc => <<-DOC + This converts a string to a boolean. This attempt to convert strings that + contain things like: Y,y, 1, T,t, TRUE,true to 'true' and strings that contain things + like: 0, F,f, N,n, false, FALSE, no to 'false'. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "str2bool(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + string = arguments[0] + + # If string is already Boolean, return it + if !!string == string # rubocop:disable Style/DoubleNegation : No viable alternative + return string + end + + unless string.is_a?(String) + raise(Puppet::ParseError, 'str2bool(): Requires 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 %r{^$}, '' then false # Empty string will be false ... + when %r{^(1|t|y|true|yes)$}i then true + when %r{^(0|f|n|false|no)$}i then false + when %r{^(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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb new file mode 100644 index 0000000..4d62008 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb @@ -0,0 +1,30 @@ +# +# str2saltedsha512.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-DOC + 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. + DOC + ) 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strftime.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strftime.rb new file mode 100644 index 0000000..53cf749 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strftime.rb @@ -0,0 +1,105 @@ +# +# strftime.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:strftime, :type => :rvalue, :doc => <<-DOC + 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 + DOC + ) 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.empty? + + 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 && !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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strip.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strip.rb new file mode 100644 index 0000000..6a147cd --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/strip.rb @@ -0,0 +1,35 @@ +# +# strip.rb +# +module Puppet::Parser::Functions + newfunction(:strip, :type => :rvalue, :doc => <<-DOC + This function removes leading and trailing whitespace from a string or from + every string inside an array. + + *Examples:* + + strip(" aaa ") + + Would result in: "aaa" + DOC + ) do |arguments| + + raise(Puppet::ParseError, "strip(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'strip(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + value.map { |i| i.is_a?(String) ? i.strip : i } + else + value.strip + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/suffix.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/suffix.rb new file mode 100644 index 0000000..407cd53 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/suffix.rb @@ -0,0 +1,51 @@ +# +# suffix.rb +# +module Puppet::Parser::Functions + newfunction(:suffix, :type => :rvalue, :doc => <<-DOC + This function applies a suffix to all elements in an array, or to the keys + in a hash. + + *Examples:* + + suffix(['a','b','c'], 'p') + + Will return: ['ap','bp','cp'] + DOC + ) 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.empty? + + enumerable = arguments[0] + + unless enumerable.is_a?(Array) || enumerable.is_a?(Hash) + raise Puppet::ParseError, "suffix(): expected first argument to be an Array or a Hash, got #{enumerable.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 + + result = if enumerable.is_a?(Array) + # Turn everything into string same as join would do ... + enumerable.map do |i| + i = i.to_s + suffix ? i + suffix : i + end + else + Hash[enumerable.map do |k, v| + k = k.to_s + [suffix ? k + suffix : k, v] + end] + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/swapcase.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/swapcase.rb new file mode 100644 index 0000000..e8a5d9a --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/swapcase.rb @@ -0,0 +1,36 @@ +# +# swapcase.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:swapcase, :type => :rvalue, :doc => <<-DOC + This function will swap the existing case of a string. + + *Examples:* + + swapcase("aBcD") + + Would result in: "AbCd" + DOC + ) do |arguments| + + raise(Puppet::ParseError, "swapcase(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'swapcase(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? i.swapcase : i } + else + value.swapcase + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/time.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/time.rb new file mode 100644 index 0000000..021a483 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/time.rb @@ -0,0 +1,48 @@ +# +# time.rb +# +module Puppet::Parser::Functions + newfunction(:time, :type => :rvalue, :doc => <<-DOC + This function will return the current time since epoch as an integer. + + *Examples:* + + time() + + Will return something like: 1311972653 + DOC + ) do |arguments| + + # The Time Zone argument is optional ... + time_zone = arguments[0] if arguments[0] + + if !arguments.empty? && (arguments.size != 1) + 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 && !time_zone.empty? + original_zone = ENV['TZ'] + + local_time = time.clone + local_time = local_time.utc + + ENV['TZ'] = time_zone + + result = local_time.localtime.strftime('%s') + + ENV['TZ'] = original_zone + else + result = time.localtime.strftime('%s') + end + + # Calling Time#to_i on a receiver changes it. Trust me I am the Doctor. + result = result.to_i + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb new file mode 100644 index 0000000..bff24b0 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb @@ -0,0 +1,33 @@ +# +# to_bytes.rb +# +module Puppet::Parser::Functions + newfunction(:to_bytes, :type => :rvalue, :doc => <<-DOC + Converts the argument into bytes, for example 4 kB becomes 4096. + Takes a single string value as an argument. + These conversions reflect a layperson's understanding of + 1 MB = 1024 KB, when in fact 1 MB = 1000 KB, and 1 MiB = 1024 KiB. + DOC + ) 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 = *%r{([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 'P' then return (value * (1 << 50)).to_i + when 'E' then return (value * (1 << 60)).to_i + else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}" + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/try_get_value.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/try_get_value.rb new file mode 100644 index 0000000..34f9476 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/try_get_value.rb @@ -0,0 +1,56 @@ +# +# try_get_value.rb +# +module Puppet::Parser::Functions + newfunction( + :try_get_value, + :type => :rvalue, + :arity => -2, + :doc => <<-DOC + DEPRECATED: this function is deprecated, please use dig() instead. + + Looks up into a complex structure of arrays and hashes and returns a value + or the default value if nothing was found. + + Key can contain slashes to describe path components. The function will go down + the structure and try to extract the required value. + + $data = { + 'a' => { + 'b' => [ + 'b1', + 'b2', + 'b3', + ] + } + } + + $value = try_get_value($data, 'a/b/2', 'not_found', '/') + => $value = 'b3' + + a -> first hash key + b -> second hash key + 2 -> array index starting with 0 + + not_found -> (optional) will be returned if there is no value or the path did not match. Defaults to nil. + / -> (optional) path delimiter. Defaults to '/'. + + In addition to the required "key" argument, "try_get_value" accepts default + argument. It will be returned if no value was found or a path component is + missing. And the fourth argument can set a variable path separator. + DOC + ) do |args| + warning('try_get_value() DEPRECATED: this function is deprecated, please use dig() instead.') + data = args[0] + path = args[1] || '' + default = args[2] + + if !(data.is_a?(Hash) || data.is_a?(Array)) || path == '' + return default || data + end + + separator = args[3] || '/' + path = path.split(separator).map { |key| (key =~ %r{^\d+$}) ? key.to_i : key } + function_dig([data, path, default]) + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type.rb new file mode 100644 index 0000000..d9d841b --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type.rb @@ -0,0 +1,18 @@ +# +# type.rb +# +module Puppet::Parser::Functions + newfunction(:type, :type => :rvalue, :doc => <<-DOC + DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system. + DOC + ) do |args| + + warning("type() DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.") # rubocop:disable Metrics/LineLength : Cannot reduce line length + unless Puppet::Parser::Functions.autoloader.loaded?(:type3x) + Puppet::Parser::Functions.autoloader.load(:type3x) + end + function_type3x(args) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type3x.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type3x.rb new file mode 100644 index 0000000..f5b46aa --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/type3x.rb @@ -0,0 +1,49 @@ +# +# type3x.rb +# +module Puppet::Parser::Functions + newfunction(:type3x, :type => :rvalue, :doc => <<-DOC + DEPRECATED: This function will be removed when puppet 3 support is dropped; please migrate to the new parser's typing system. + + Returns the type when passed a value. Type can be one of: + + * string + * array + * hash + * float + * integer + * boolean + DOC + ) do |args| + raise(Puppet::ParseError, "type3x(): Wrong number of arguments given (#{args.size} for 1)") unless args.size == 1 + + value = args[0] + + klass = value.class + + unless [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass) # rubocop:disable Lint/UnifiedInteger + raise(Puppet::ParseError, 'type3x(): Unknown type') + end + + klass = klass.to_s # Ugly ... + + # We note that Integer is the parent to Bignum and Fixnum ... + result = case klass + when %r{^(?:Big|Fix)num$} then 'integer' + when %r{^(?:True|False)Class$} then 'boolean' + else klass + end + + if result == 'String' + if value == value.to_i.to_s + result = 'Integer' + elsif value == value.to_f.to_s + result = 'Float' + end + end + + return result.downcase + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/union.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/union.rb new file mode 100644 index 0000000..ed57bc5 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/union.rb @@ -0,0 +1,27 @@ +# +# union.rb +# +module Puppet::Parser::Functions + newfunction(:union, :type => :rvalue, :doc => <<-DOC + This function returns a union of two or more arrays. + + *Examples:* + + union(["a","b","c"],["b","c","d"]) + + Would return: ["a","b","c","d"] + DOC + ) do |arguments| + + # Check that 2 or more arguments have been given ... + raise(Puppet::ParseError, "union(): Wrong number of arguments given (#{arguments.size} for < 2)") if arguments.size < 2 + + arguments.each do |argument| + raise(Puppet::ParseError, 'union(): Every parameter must be an array') unless argument.is_a?(Array) + end + + arguments.reduce(:|) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unique.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unique.rb new file mode 100644 index 0000000..301f6a4 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unique.rb @@ -0,0 +1,51 @@ +# +# unique.rb +# +module Puppet::Parser::Functions + newfunction(:unique, :type => :rvalue, :doc => <<-DOC + 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"] + DOC + ) do |arguments| + + if Puppet::Util::Package.versioncmp(Puppet.version, '5.0.0') >= 0 + function_deprecation([:unique, 'This method is deprecated, please use the core puppet unique function. There is further documentation for the function in the release notes of Puppet 5.0.']) + end + + raise(Puppet::ParseError, "unique(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unix2dos.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unix2dos.rb new file mode 100644 index 0000000..8123797 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/unix2dos.rb @@ -0,0 +1,15 @@ +# Custom Puppet function to convert unix to dos format +module Puppet::Parser::Functions + newfunction(:unix2dos, :type => :rvalue, :arity => 1, :doc => <<-DOC + Returns the DOS version of the given string. + Takes a single string argument. + DOC + ) do |arguments| + + unless arguments[0].is_a?(String) + raise(Puppet::ParseError, 'unix2dos(): Requires string as argument') + end + + arguments[0].gsub(%r{\r*\n}, "\r\n") + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/upcase.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/upcase.rb new file mode 100644 index 0000000..42e6114 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/upcase.rb @@ -0,0 +1,43 @@ +# +# upcase.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:upcase, :type => :rvalue, :doc => <<-DOC + Converts a string or an array of strings to uppercase. + + *Examples:* + + upcase("abcd") + + Will return: + + ABCD + DOC + ) do |arguments| + + raise(Puppet::ParseError, "upcase(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(Hash) || value.respond_to?(:upcase) + raise(Puppet::ParseError, 'upcase(): Requires an array, hash or object that responds to upcase in order to work') + end + + if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + result = value.map { |i| function_upcase([i]) } + elsif value.is_a?(Hash) + result = {} + value.each_pair do |k, v| + result[function_upcase([k])] = function_upcase([v]) + end + else + result = value.upcase + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/uriescape.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/uriescape.rb new file mode 100644 index 0000000..8bcd586 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/uriescape.rb @@ -0,0 +1,32 @@ +require 'uri' +# +# uriescape.rb +# Please note: This function is an implementation of a Ruby class and as such may not be entirely UTF8 compatible. To ensure compatibility please use this function with Ruby 2.4.0 or greater - https://bugs.ruby-lang.org/issues/10085. +# +module Puppet::Parser::Functions + newfunction(:uriescape, :type => :rvalue, :doc => <<-DOC + Urlencodes a string or array of strings. + Requires either a single string or an array as an input. + DOC + ) do |arguments| + + raise(Puppet::ParseError, "uriescape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + value = arguments[0] + + unless value.is_a?(Array) || value.is_a?(String) + raise(Puppet::ParseError, 'uriescape(): Requires either array or string to work with') + end + + result = if value.is_a?(Array) + # Numbers in Puppet are often string-encoded which is troublesome ... + value.map { |i| i.is_a?(String) ? URI.escape(i) : i } + else + URI.escape(value) + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb new file mode 100644 index 0000000..0db10c3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb @@ -0,0 +1,54 @@ +# +# validate_absolute_path.rb +# +module Puppet::Parser::Functions + newfunction(:validate_absolute_path, :doc => <<-'DOC') 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) + $my_path3 = ['C:/Program Files (x86)/Puppet Labs/Puppet','C:/Program Files/Puppet Labs/Puppet'] + validate_absolute_path($my_path3) + $my_path4 = ['/var/lib/puppet','/usr/share/puppet'] + validate_absolute_path($my_path4) + + The following values will fail, causing compilation to abort: + + validate_absolute_path(true) + validate_absolute_path('../var/lib/puppet') + validate_absolute_path('var/lib/puppet') + validate_absolute_path([ 'var/lib/puppet', '/var/foo' ]) + validate_absolute_path([ '/var/lib/puppet', 'var/foo' ]) + $undefined = undef + validate_absolute_path($undefined) + + DOC + + require 'puppet/util' + + if args.empty? + raise Puppet::ParseError, "validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + # put arg to candidate var to be able to replace it + candidates = arg + # if arg is just a string with a path to test, convert it to an array + # to avoid test code duplication + unless arg.is_a?(Array) + candidates = Array.new(1, arg) + end + # iterate over all paths within the candidates array + candidates.each do |path| + unless function_is_absolute_path([path]) + raise Puppet::ParseError, "#{path.inspect} is not an absolute path." + end + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_array.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_array.rb new file mode 100644 index 0000000..1120ce8 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_array.rb @@ -0,0 +1,36 @@ +# +# validate_array.rb +# +module Puppet::Parser::Functions + newfunction(:validate_array, :doc => <<-'DOC') 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) + + DOC + + function_deprecation([:validate_array, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Array. There is further documentation for validate_legacy function in the README.']) + + if args.empty? + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb new file mode 100644 index 0000000..97f3127 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb @@ -0,0 +1,86 @@ +require 'tempfile' + +# +# validate_augaes.rb +# +module Puppet::Parser::Functions + newfunction(:validate_augeas, :doc => <<-'DOC') 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') + + DOC + unless Puppet.features.augeas? + raise Puppet::ParseError, 'validate_augeas(): this function requires the augeas feature. See http://docs.puppetlabs.com/guides/augeas.html#pre-requisites for how to activate it.' + end + + if (args.length < 2) || (args.length > 4) + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb new file mode 100644 index 0000000..d3bf3d0 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb @@ -0,0 +1,34 @@ +# +# validate_bool.rb +# +module Puppet::Parser::Functions + newfunction(:validate_bool, :doc => <<-'DOC') 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) + + DOC + + if args.empty? + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb new file mode 100644 index 0000000..dbea604 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb @@ -0,0 +1,66 @@ +require 'puppet/util/execution' +require 'tempfile' + +# +# validate_cmd.rb +# +module Puppet::Parser::Functions + newfunction(:validate_cmd, :doc => <<-'DOC') 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 % as a placeholder for the file path (will default to the end). + If the command, launched against a tempfile containing the passed string, + returns a non-null value, compilation will abort with a parse error. + + If a third argument is specified, this will be the error message raised and + seen by the user. + + A helpful error message can be returned like this: + + Example: + + # Defaults to end of path + validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content') + + # % as file location + validate_cmd($haproxycontent, '/usr/sbin/haproxy -f % -c', 'Haproxy failed to validate config content') + + DOC + if (args.length < 2) || (args.length > 3) + 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 + + check_with_correct_location = if checkscript =~ %r{\s%(\s|$)} + checkscript.gsub(%r{%}, tmpfile.path) + else + "#{checkscript} #{tmpfile.path}" + end + + if Puppet::Util::Execution.respond_to?('execute') + Puppet::Util::Execution.execute(check_with_correct_location) + else + Puppet::Util.execute(check_with_correct_location) + end + rescue Puppet::ExecutionFailure => detail + msg += "\n#{detail}" + raise Puppet::ParseError, msg + rescue StandardError => detail + msg += "\n#{detail.class.name} #{detail}" + raise Puppet::ParseError, msg + ensure + tmpfile.unlink + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_domain_name.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_domain_name.rb new file mode 100644 index 0000000..c479dfb --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_domain_name.rb @@ -0,0 +1,42 @@ +# +# validate_domain_name.rb +# +module Puppet::Parser::Functions + newfunction(:validate_domain_name, :doc => <<-DOC + Validate that all values passed are syntactically correct domain names. + Fail compilation if any value fails this check. + + The following values will pass: + + $my_domain_name = 'server.domain.tld' + validate_domain_name($my_domain_name) + validate_domain_name('domain.tld', 'puppet.com', $my_domain_name) + + The following values will fail, causing compilation to abort: + + validate_domain_name(1) + validate_domain_name(true) + validate_domain_name('invalid domain') + validate_domain_name('-foo.example.com') + validate_domain_name('www.example.2com') + + DOC + ) do |args| + + rescuable_exceptions = [ArgumentError] + + if args.empty? + raise Puppet::ParseError, "validate_domain_name(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + raise Puppet::ParseError, "#{arg.inspect} is not a string." unless arg.is_a?(String) + + begin + raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name" unless function_is_domain_name([arg]) + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name" + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_email_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_email_address.rb new file mode 100644 index 0000000..a039f51 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_email_address.rb @@ -0,0 +1,34 @@ +# +# validate_email_address.rb +# +module Puppet::Parser::Functions + newfunction(:validate_email_address, :doc => <<-DOC + Validate that all values passed are valid email addresses. + Fail compilation if any value fails this check. + The following values will pass: + $my_email = "waldo@gmail.com" + validate_email_address($my_email) + validate_email_address("bob@gmail.com", "alice@gmail.com", $my_email) + + The following values will fail, causing compilation to abort: + $some_array = [ 'bad_email@/d/efdf.com' ] + validate_email_address($some_array) + DOC + ) do |args| + rescuable_exceptions = [ArgumentError] + + if args.empty? + raise Puppet::ParseError, "validate_email_address(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + raise Puppet::ParseError, "#{arg.inspect} is not a string." unless arg.is_a?(String) + + begin + raise Puppet::ParseError, "#{arg.inspect} is not a valid email address" unless function_is_email_address([arg]) + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid email address" + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb new file mode 100644 index 0000000..0460cf3 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb @@ -0,0 +1,36 @@ +# +# validate_hash.rb +# +module Puppet::Parser::Functions + newfunction(:validate_hash, :doc => <<-'DOC') 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) + + DOC + + function_deprecation([:validate_hash, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Hash. There is further documentation for validate_legacy function in the README.']) + + if args.empty? + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_integer.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_integer.rb new file mode 100644 index 0000000..fc50bdc --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_integer.rb @@ -0,0 +1,137 @@ +# +# validate_interger.rb +# +module Puppet::Parser::Functions + newfunction(:validate_integer, :doc => <<-'DOC') do |args| + Validate that the first argument is an integer (or an array of integers). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not an integer or array of integers, and if arg 2 and arg 3 are not convertable to an integer. + + The following values will pass: + + validate_integer(1) + validate_integer(1, 2) + validate_integer(1, 1) + validate_integer(1, 2, 0) + validate_integer(2, 2, 2) + validate_integer(2, '', 0) + validate_integer(2, undef, 0) + $foo = undef + validate_integer(2, $foo, 0) + validate_integer([1,2,3,4,5], 6) + validate_integer([1,2,3,4,5], 6, 0) + + Plus all of the above, but any combination of values passed as strings ('1' or "1"). + Plus all of the above, but with (correct) combinations of negative integer values. + + The following values will not: + + validate_integer(true) + validate_integer(false) + validate_integer(7.0) + validate_integer({ 1 => 2 }) + $foo = undef + validate_integer($foo) + validate_integer($foobaridontexist) + + validate_integer(1, 0) + validate_integer(1, true) + validate_integer(1, '') + validate_integer(1, undef) + validate_integer(1, , 0) + validate_integer(1, 2, 3) + validate_integer(1, 3, 2) + validate_integer(1, 3, true) + + Plus all of the above, but any combination of values passed as strings ('false' or "false"). + Plus all of the above, but with incorrect combinations of negative integer values. + Plus all of the above, but with non-integer items in arrays or maximum / minimum argument. + + DOC + + function_deprecation([:validate_integer, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Integer. There is further documentation for validate_legacy function in the README.']) + + # tell the user we need at least one, and optionally up to two other parameters + raise Puppet::ParseError, "validate_integer(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless !args.empty? && args.length < 4 + + input, max, min = *args + + # check maximum parameter + if args.length > 1 + max = max.to_s + # allow max to be empty (or undefined) if we have a minimum set + if args.length > 2 && max == '' + max = nil + else + begin + max = Integer(max) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected second argument to be unset or an Integer, got #{max}:#{max.class}" + end + end + else + max = nil + end + + # check minimum parameter + if args.length > 2 + begin + min = Integer(min.to_s) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected third argument to be unset or an Integer, got #{min}:#{min.class}" + end + else + min = nil + end + + # ensure that min < max + if min && max && min > max + raise Puppet::ParseError, "validate_integer(): Expected second argument to be larger than third argument, got #{max} < #{min}" + end + + # create lamba validator function + validator = ->(num) do + # check input < max + if max && num > max + raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}." + end + # check input > min (this will only be checked if no exception has been raised before) + if min && num < min + raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}." + end + end + + # if this is an array, handle it. + case input + when Array + # check every element of the array + input.each_with_index do |arg, pos| + begin + raise TypeError if arg.is_a?(Hash) + arg = Integer(arg.to_s) + validator.call(arg) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected element at array position #{pos} to be an Integer, got #{arg.class}" + end + end + # for the sake of compatibility with ruby 1.8, we need extra handling of hashes + when Hash + raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}" + # check the input. this will also fail any stuff other than pure, shiny integers + else + begin + input = Integer(input.to_s) + validator.call(input) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}" + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ip_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ip_address.rb new file mode 100644 index 0000000..af835ad --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ip_address.rb @@ -0,0 +1,53 @@ +# +# validate_ip_address.rb +# +module Puppet::Parser::Functions + newfunction(:validate_ip_address, :doc => <<-DOC + Validate that all values passed are valid IP addresses, + regardless they are IPv4 or IPv6 + Fail compilation if any value fails this check. + The following values will pass: + $my_ip = "1.2.3.4" + validate_ip_address($my_ip) + validate_ip_address("8.8.8.8", "172.16.0.1", $my_ip) + + $my_ip = "3ffe:505:2" + validate_ip_address(1) + validate_ip_address($my_ip) + validate_ip_address("fe80::baf6:b1ff:fe19:7507", $my_ip) + + The following values will fail, causing compilation to abort: + $some_array = [ 1, true, false, "garbage string", "3ffe:505:2" ] + validate_ip_address($some_array) + DOC + ) do |args| + + require 'ipaddr' + rescuable_exceptions = [ArgumentError] + + function_deprecation([:validate_ip_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ip_address. There is further documentation for validate_legacy function in the README.']) + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + if args.empty? + raise Puppet::ParseError, "validate_ip_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? || IPAddr.new(arg).ipv6? + raise Puppet::ParseError, "#{arg.inspect} is not a valid IP address." + end + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid IP address." + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb new file mode 100644 index 0000000..1ac303f --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb @@ -0,0 +1,51 @@ +# +# validate_ipv4_address.rb +# +module Puppet::Parser::Functions + newfunction(:validate_ipv4_address, :doc => <<-DOC + 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_ipv4_address("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) + + DOC + ) do |args| + + function_deprecation([:validate_ipv4_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv4. There is further documentation for validate_legacy function in the README.']) + + require 'ipaddr' + rescuable_exceptions = [ArgumentError] + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + if args.empty? + raise Puppet::ParseError, "validate_ipv4_address(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + unless arg.is_a?(String) + raise Puppet::ParseError, "#{arg.inspect} is not a string." + end + + begin + unless IPAddr.new(arg).ipv4? + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address." + end + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address." + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb new file mode 100644 index 0000000..88c133c --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb @@ -0,0 +1,52 @@ +# +# validate_ipv7_address.rb +# +module Puppet::Parser::Functions + newfunction(:validate_ipv6_address, :doc => <<-DOC + 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) + + DOC + ) do |args| + + function_deprecation([:validate_ipv6_address, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Ipv6. There is further documentation for validate_legacy function in the README.']) + + require 'ipaddr' + rescuable_exceptions = [ArgumentError] + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + + if args.empty? + raise Puppet::ParseError, "validate_ipv6_address(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + unless arg.is_a?(String) + raise Puppet::ParseError, "#{arg.inspect} is not a string." + end + + begin + unless IPAddr.new(arg).ipv6? + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address." + end + rescue *rescuable_exceptions + raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address." + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_numeric.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_numeric.rb new file mode 100644 index 0000000..803e6f0 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_numeric.rb @@ -0,0 +1,99 @@ +# +# validate_numeric.rb +# +module Puppet::Parser::Functions + newfunction(:validate_numeric, :doc => <<-'DOC') do |args| + Validate that the first argument is a numeric value (or an array of numeric values). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not a numeric (Integer or Float) or array of numerics, and if arg 2 and arg 3 are not convertable to a numeric. + + For passing and failing usage, see `validate_integer()`. It is all the same for validate_numeric, yet now floating point values are allowed, too. + + DOC + + function_deprecation([:validate_numeric, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Numeric. There is further documentation for validate_legacy function in the README.']) + + # tell the user we need at least one, and optionally up to two other parameters + raise Puppet::ParseError, "validate_numeric(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless !args.empty? && args.length < 4 + + input, max, min = *args + + # check maximum parameter + if args.length > 1 + max = max.to_s + # allow max to be empty (or undefined) if we have a minimum set + if args.length > 2 && max == '' + max = nil + else + begin + max = Float(max) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected second argument to be unset or a Numeric, got #{max}:#{max.class}" + end + end + else + max = nil + end + + # check minimum parameter + if args.length > 2 + begin + min = Float(min.to_s) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected third argument to be unset or a Numeric, got #{min}:#{min.class}" + end + else + min = nil + end + + # ensure that min < max + if min && max && min > max + raise Puppet::ParseError, "validate_numeric(): Expected second argument to be larger than third argument, got #{max} < #{min}" + end + + # create lamba validator function + validator = ->(num) do + # check input < max + if max && num > max + raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}." + end + # check input > min (this will only be checked if no exception has been raised before) + if min && num < min + raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}." + end + end + + # if this is an array, handle it. + case input + when Array + # check every element of the array + input.each_with_index do |arg, pos| + begin + raise TypeError if arg.is_a?(Hash) + arg = Float(arg.to_s) + validator.call(arg) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected element at array position #{pos} to be a Numeric, got #{arg.class}" + end + end + # for the sake of compatibility with ruby 1.8, we need extra handling of hashes + when Hash + raise Puppet::ParseError, "validate_integer(): Expected first argument to be a Numeric or Array, got #{input.class}" + # check the input. this will also fail any stuff other than pure, shiny integers + else + begin + input = Float(input.to_s) + validator.call(input) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected first argument to be a Numeric or Array, got #{input.class}" + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_re.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_re.rb new file mode 100644 index 0000000..88f23fc --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_re.rb @@ -0,0 +1,53 @@ +# +# validate.rb +# +module Puppet::Parser::Functions + newfunction(:validate_re, :doc => <<-'DOC') 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') + + Note: Compilation will also abort, if the first argument is not a String. Always use + quotes to force stringification: + + validate_re("${::operatingsystemmajrelease}", '^[57]$') + + DOC + + function_deprecation([:validate_re, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::Re. There is further documentation for validate_legacy function in the README.']) + + if (args.length < 2) || (args.length > 3) + raise Puppet::ParseError, "validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)" + end + + raise Puppet::ParseError, "validate_re(): input needs to be a String, not a #{args[0].class}" unless args[0].is_a? String + + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb new file mode 100644 index 0000000..db5010e --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb @@ -0,0 +1,71 @@ +# +# validate_slength.rb +# +module Puppet::Parser::Functions + newfunction(:validate_slength, :doc => <<-'DOC') 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 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) + + DOC + + function_deprecation([:validate_slength, 'This method is deprecated, please use the stdlib validate_legacy function, + with String[]. There is further documentation for validate_legacy function in the README.']) + + raise Puppet::ParseError, "validate_slength(): Wrong number of arguments (#{args.length}; must be 2 or 3)" unless args.length == 2 || 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 + + raise Puppet::ParseError, 'validate_slength(): Expected second argument to be equal to or larger than third argument' unless max_length >= min_length + + validator = ->(str) do + unless str.length <= max_length && 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| + raise Puppet::ParseError, "validate_slength(): Expected element at array position #{pos} to be a String, got #{arg.class}" unless arg.is_a? String + validator.call(arg) + end + else + raise Puppet::ParseError, "validate_slength(): Expected first argument to be a String or Array, got #{input.class}" + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_string.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_string.rb new file mode 100644 index 0000000..c2847b6 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_string.rb @@ -0,0 +1,42 @@ +# +# validate_String.rb +# +module Puppet::Parser::Functions + newfunction(:validate_string, :doc => <<-'DOC') 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' ]) + + Note: validate_string(undef) will not fail in this version of the + functions API (incl. current and future parser). Instead, use: + + if $var == undef { + fail('...') + } + + DOC + + function_deprecation([:validate_string, 'This method is deprecated, please use the stdlib validate_legacy function, + with Stdlib::Compat::String. There is further documentation for validate_legacy function in the README.']) + + if args.empty? + raise Puppet::ParseError, "validate_string(): wrong number of arguments (#{args.length}; must be > 0)" + end + + args.each do |arg| + # when called through the v4 API shim, undef gets translated to nil + unless arg.is_a?(String) || arg.nil? + raise Puppet::ParseError, "#{arg.inspect} is not a string. It looks to be a #{arg.class}" + end + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_x509_rsa_key_pair.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_x509_rsa_key_pair.rb new file mode 100644 index 0000000..ea69dc4 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/validate_x509_rsa_key_pair.rb @@ -0,0 +1,48 @@ +# +# validate_x509_rsa_key_pair.rb +# +module Puppet::Parser::Functions + newfunction(:validate_x509_rsa_key_pair, :doc => <<-DOC + Validates a PEM-formatted X.509 certificate and RSA private key using + OpenSSL. Verifies that the certficate's signature was created from the + supplied key. + + Fail compilation if any value fails this check. + + validate_x509_rsa_key_pair($cert, $key) + + DOC + ) do |args| + + require 'openssl' + + NUM_ARGS = 2 unless defined? NUM_ARGS + + unless args.length == NUM_ARGS + raise Puppet::ParseError, + "validate_x509_rsa_key_pair(): wrong number of arguments (#{args.length}; must be #{NUM_ARGS})" + end + + args.each do |arg| + unless arg.is_a?(String) + raise Puppet::ParseError, "#{arg.inspect} is not a string." + end + end + + begin + cert = OpenSSL::X509::Certificate.new(args[0]) + rescue OpenSSL::X509::CertificateError => e + raise Puppet::ParseError, "Not a valid x509 certificate: #{e}" + end + + begin + key = OpenSSL::PKey::RSA.new(args[1]) + rescue OpenSSL::PKey::RSAError => e + raise Puppet::ParseError, "Not a valid RSA key: #{e}" + end + + unless cert.verify(key) + raise Puppet::ParseError, 'Certificate signature does not match supplied key' + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values.rb new file mode 100644 index 0000000..168da84 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values.rb @@ -0,0 +1,37 @@ +# +# values.rb +# +module Puppet::Parser::Functions + newfunction(:values, :type => :rvalue, :doc => <<-DOC + 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] + DOC + ) do |arguments| + + raise(Puppet::ParseError, "values(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.empty? + + 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 : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values_at.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values_at.rb new file mode 100644 index 0000000..2e07552 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/values_at.rb @@ -0,0 +1,89 @@ +# +# values_at.rb +# +module Puppet::Parser::Functions + newfunction(:values_at, :type => :rvalue, :doc => <<-DOC + 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']. + DOC + ) 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 !indices || indices.empty? + raise(Puppet::ParseError, 'values_at(): You must provide at least one positive index to collect') + end + + indices_list = [] + + indices.each do |i| + i = i.to_s + m = i.match(%r{^(\d+)(\.\.\.?|\-)(\d+)$}) + if m + start = m[1].to_i + stop = m[3].to_i + + type = m[2] + + raise(Puppet::ParseError, 'values_at(): Stop index in given indices range is smaller than the start index') if start > stop + raise(Puppet::ParseError, 'values_at(): Stop index in given indices range exceeds array size') if stop > array.size - 1 # First element is at index 0 is it not? + + range = case type + when %r{^(\.\.|\-)$} then (start..stop) + when %r{^(\.\.\.)$} then (start...stop) # Exclusive of last element ... + end + + range.each { |i| indices_list << i.to_i } # rubocop:disable Lint/ShadowingOuterLocalVariable : Value is meant to be shadowed + else + # Only positive numbers allowed in this case ... + unless i =~ %r{^\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.map { |i| array[i] }.compact + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/parser/functions/zip.rb b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/zip.rb new file mode 100644 index 0000000..87a89f8 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/parser/functions/zip.rb @@ -0,0 +1,37 @@ +# +# zip.rb +# +module Puppet::Parser::Functions + newfunction(:zip, :type => :rvalue, :doc => <<-DOC + 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"] + DOC + ) 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) && b.is_a?(Array) + raise(Puppet::ParseError, 'zip(): Requires array to work with') + end + + flatten = function_str2bool([arguments[2]]) if arguments[2] + + result = a.zip(b) + result = flatten ? result.flatten : result + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/code/environments/production/modules/stdlib/lib/puppet/provider/file_line/ruby.rb b/code/environments/production/modules/stdlib/lib/puppet/provider/file_line/ruby.rb new file mode 100644 index 0000000..8423300 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/provider/file_line/ruby.rb @@ -0,0 +1,171 @@ +Puppet::Type.type(:file_line).provide(:ruby) do + def exists? + found = false + lines_count = 0 + lines.each do |line| + found = line.chomp == resource[:line] + if found + lines_count += 1 + end + end + return found = lines_count > 0 if resource[:match].nil? + + match_count = count_matches(new_match_regex) + found = if resource[:ensure] == :present + if match_count.zero? + if lines_count.zero? && resource[:append_on_no_match].to_s == 'false' + true # lies, but gets the job done + elsif lines_count.zero? && resource[:append_on_no_match].to_s != 'false' + false + else + true + end + elsif resource[:replace_all_matches_not_matching_line].to_s == 'true' + false # maybe lies, but knows there's still work to do + elsif lines_count.zero? + resource[:replace].to_s == 'false' + else + true + end + elsif match_count.zero? + if lines_count.zero? + false + else + true + end + elsif lines_count.zero? + resource[:match_for_absence].to_s == 'true' + else + true + end + end + + def create + return if resource[:replace].to_s != 'true' && count_matches(new_match_regex) > 0 + if resource[:match] + handle_create_with_match + elsif resource[:after] + handle_create_with_after + else + handle_append_line + end + end + + def destroy + if resource[:match_for_absence].to_s == 'true' && resource[:match] + handle_destroy_with_match + else + handle_destroy_line + 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], :encoding => resource[:encoding]) + rescue TypeError => _e + # Ruby 1.8 doesn't support open_args + @lines ||= File.readlines(resource[:path]) + end + + def new_after_regex + resource[:after] ? Regexp.new(resource[:after]) : nil + end + + def new_match_regex + resource[:match] ? Regexp.new(resource[:match]) : nil + end + + def count_matches(regex) + lines.select { |line| + if resource[:replace_all_matches_not_matching_line].to_s == 'true' + line.match(regex) unless line.chomp == resource[:line] + else + line.match(regex) + end + }.size + end + + def handle_create_with_match + after_regex = new_after_regex + match_regex = new_match_regex + match_count = count_matches(new_match_regex) + + if match_count > 1 && resource[:multiple].to_s != 'true' + raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" + end + + File.open(resource[:path], 'w') do |fh| + lines.each do |line| + fh.puts(match_regex.match(line) ? resource[:line] : line) + next unless match_count.zero? && after_regex + if after_regex.match(line) + fh.puts(resource[:line]) + match_count += 1 # Increment match_count to indicate that the new line has been inserted. + end + end + + if match_count.zero? + fh.puts(resource[:line]) + end + end + end + + def handle_create_with_after + after_regex = new_after_regex + after_count = count_matches(after_regex) + + if after_count > 1 && resource[:multiple].to_s != 'true' + raise Puppet::Error, "#{after_count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern." + end + + File.open(resource[:path], 'w') do |fh| + lines.each do |line| + fh.puts(line) + if after_regex.match(line) + fh.puts(resource[:line]) + end + end + + if after_count.zero? + fh.puts(resource[:line]) + end + end + end + + def handle_destroy_with_match + match_regex = new_match_regex + match_count = count_matches(match_regex) + if match_count > 1 && resource[:multiple].to_s != 'true' + raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" + end + + local_lines = lines + File.open(resource[:path], 'w') do |fh| + fh.write(local_lines.reject { |line| match_regex.match(line) }.join('')) + end + end + + def handle_destroy_line + local_lines = lines + File.open(resource[:path], 'w') do |fh| + fh.write(local_lines.reject { |line| line.chomp == resource[:line] }.join('')) + end + end + + def handle_append_line + local_lines = lines + File.open(resource[:path], 'w') do |fh| + local_lines.each do |line| + fh.puts(line) + end + fh.puts(resource[:line]) + end + end +end diff --git a/code/environments/production/modules/stdlib/lib/puppet/type/anchor.rb b/code/environments/production/modules/stdlib/lib/puppet/type/anchor.rb new file mode 100644 index 0000000..60cfa64 --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/type/anchor.rb @@ -0,0 +1,46 @@ +Puppet::Type.newtype(:anchor) do + desc <<-'DESCRIPTION' + 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': } + + DESCRIPTION + + 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 diff --git a/code/environments/production/modules/stdlib/lib/puppet/type/file_line.rb b/code/environments/production/modules/stdlib/lib/puppet/type/file_line.rb new file mode 100644 index 0000000..14650fe --- /dev/null +++ b/code/environments/production/modules/stdlib/lib/puppet/type/file_line.rb @@ -0,0 +1,192 @@ +Puppet::Type.newtype(:file_line) do + desc <<-DOC + 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 append the line to + the end of the file to ensure the desired state. Multiple resources may + be declared to manage multiple lines in the same file. + + Example: + + 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. + + Match Example: + + file_line { 'bashrc_proxy': + ensure => present, + path => '/etc/bashrc', + line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128', + match => '^export\ HTTP_PROXY\=', + } + + In this code example match will look for a line beginning with export + followed by HTTP_PROXY and replace it with the value in line. + + Examples With `ensure => absent`: + + This type has two behaviors when `ensure => absent` is set. + + One possibility is to set `match => ...` and `match_for_absence => true`, + as in the following example: + + file_line { 'bashrc_proxy': + ensure => absent, + path => '/etc/bashrc', + match => '^export\ HTTP_PROXY\=', + match_for_absence => true, + } + + In this code example match will look for a line beginning with export + followed by HTTP_PROXY and delete it. If multiple lines match, an + error will be raised unless the `multiple => true` parameter is set. + + Note that the `line => ...` parameter would be accepted BUT IGNORED in + the above example. + + The second way of using `ensure => absent` is to specify a `line => ...`, + and no match: + + file_line { 'bashrc_proxy': + ensure => absent, + path => '/etc/bashrc', + line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128', + } + + Note that when ensuring lines are absent this way, the default behavior + this time is to always remove all lines matching, and this behavior + can't be disabled. + + Encoding example: + + file_line { "XScreenSaver": + ensure => present, + path => '/root/XScreenSaver', + line => "*lock: 10:00:00", + match => '^*lock:', + encoding => "iso-8859-1", + } + + Files with special characters that are not valid UTF-8 will give the + error message "invalid byte sequence in UTF-8". In this case, determine + the correct file encoding and specify the correct encoding using the + encoding attribute, the value of which needs to be a valid Ruby character + encoding. + + **Autorequires:** If Puppet is managing the file that will contain the line + being managed, the file_line resource will autorequire that file. + DOC + + 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 ruby regular expression to run against existing lines in the file.' \ + ' If a match is found, we replace that line rather than adding a new line.' \ + ' A regex comparison is performed against the line value and if it does not' \ + ' match an exception will be raised.' + end + + newparam(:match_for_absence) do + desc 'An optional value to determine if match should be applied when ensure => absent.' \ + ' If set to true and match is set, the line that matches match will be deleted.' \ + ' If set to false (the default), match is ignored when ensure => absent.' \ + ' When `ensure => present`, match_for_absence is ignored.' + newvalues(true, false) + defaultto false + end + + newparam(:multiple) do + desc 'An optional value to determine if match can change multiple lines.' \ + ' If set to false, an exception will be raised if more than one line matches' + newvalues(true, false) + end + + 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)' \ + ' This is also takes a regex.' + end + + # The line property never changes; the type only ever performs a create() or + # destroy(). line is a property in order to allow it to correctly handle + # Sensitive type values. Because it is a property which will never change, + # it should never be considered out of sync. + newproperty(:line) do + desc 'The line to be appended to the file or used to replace matches found by the match attribute.' + + def retrieve + @resource[:line] + end + end + + newparam(:path) do + desc 'The file Puppet will ensure contains the line specified by the line parameter.' + validate do |value| + unless Puppet::Util.absolute_path?(value) + raise Puppet::Error, "File paths must be fully qualified, not '#{value}'" + end + end + end + + newparam(:replace) do + desc 'If true, replace line that matches. If false, do not write line if a match is found' + newvalues(true, false) + defaultto true + end + + newparam(:replace_all_matches_not_matching_line) do + desc 'Configures the behavior of replacing all lines in a file which match the `match` parameter regular expression, regardless of whether the specified line is already present in the file.' + + newvalues(true, false) + defaultto false + end + + newparam(:encoding) do + desc 'For files that are not UTF-8 encoded, specify encoding such as iso-8859-1' + defaultto 'UTF-8' + end + + newparam(:append_on_no_match) do + desc 'If true, append line if match is not found. If false, do not append line if a match is not found' + newvalues(true, false) + defaultto true + end + + # Autorequire the file resource if it's being managed + autorequire(:file) do + self[:path] + end + + validate do + if self[:replace_all_matches_not_matching_line].to_s == 'true' && self[:multiple].to_s == 'false' + raise(Puppet::Error, 'multiple must be true when replace_all_matches_not_matching_line is true') + end + if self[:replace_all_matches_not_matching_line].to_s == 'true' && self[:replace].to_s == 'false' + raise(Puppet::Error, 'replace must be true when replace_all_matches_not_matching_line is true') + end + unless self[:line] + unless (self[:ensure].to_s == 'absent') && (self[:match_for_absence].to_s == 'true') && self[:match] + raise(Puppet::Error, 'line is a required attribute') + end + end + unless self[:path] + raise(Puppet::Error, 'path is a required attribute') + end + end +end |