From 97af68e160ef9f766e690c74fc706088bbf1420f Mon Sep 17 00:00:00 2001 From: Ben Ford Date: Fri, 3 Jan 2020 18:45:13 -0800 Subject: [PATCH] Porting functions to the modern Puppet 4.x API --- .../functions/bareos/bareos_settings.rb | 167 ++++++++++++++++++ spec/functions/bareos_bareos_settings_spec.rb | 41 +++++ 2 files changed, 208 insertions(+) create mode 100644 lib/puppet/functions/bareos/bareos_settings.rb create mode 100644 spec/functions/bareos_bareos_settings_spec.rb diff --git a/lib/puppet/functions/bareos/bareos_settings.rb b/lib/puppet/functions/bareos/bareos_settings.rb new file mode 100644 index 00000000..574b9f5a --- /dev/null +++ b/lib/puppet/functions/bareos/bareos_settings.rb @@ -0,0 +1,167 @@ +# This is an autogenerated function, ported from the original legacy version. +# It /should work/ as is, but will not have all the benefits of the modern +# function API. You should see the function docs to learn how to add function +# signatures for type safety and to document this function using puppet-strings. +# +# https://puppet.com/docs/puppet/latest/custom_functions_ruby.html +# +# ---- original file header ---- +require 'resolv' + +# ---- original file header ---- +# +# @summary +# Helper function to parse settings for bareos and return prepared lines for config file +# +# +Puppet::Functions.create_function(:'bareos::bareos_settings') do + # @param args + # The original array of arguments. Port this to individually managed params + # to get the full benefit of the modern function API. + # + # @return [Data type] + # Describe what the function returns here + # + dispatch :default_impl do + # Call the method named 'default_impl' when this is matched + # Port this to match individual params for better type safety + repeated_param 'Any', :args + end + + + def default_impl(*args) + + + final_settings = [] + args.each do |setting| + begin + raise 'Invalid or incomplete setting' unless setting.length > 2 && setting.is_a?(Array) + value_setting = setting[0] # value for this setting + directive = setting[1] # Directive Keyword of this setting + dirty_type = setting[2] # bareos variable type + required = setting[3] # boolean, undef allowed or not + indent = setting[4] || ' ' # Internally used, just for beatufying + + raise 'Name of directive config key is invalid' unless directive =~ %r{^[a-zA-Z0-9 ]+$} + + # check array if allowed + values = if (%w[acl runscript].include?(dirty_type) || dirty_type =~ %r{[_-]list$}) && value_setting.is_a?(Array) + value_setting + else + [value_setting] + end + type = dirty_type.gsub(%r{([_-]list)$}, '') + + values.each do |value| + # ignore undef if not required + next if required == false && (value == nil || value == :undef) + raise 'This directive is required, please set value' if (value == nil || value == :undef) + + # defaults: + # quote value + quote = false + # check regex + regex = nil + # check in array + value_in_array = nil + # required for addresses/hashes + hash_separator = ' ' + + # validation by type + case type + # maybe check more than it is an int + when 'int32', 'pint16', 'pint32', 'port', 'max_blocksize' + # type casting raise error + Integer(value) + when 'name', 'res', 'resource' + quote = true + regex = %r{^[a-z][a-z0-9\.\-_ \$]{0,126}$}i + when 'acl', 'messages', 'type', 'string_noquote', 'schedule_run_command' + raise 'Value need to be an string' unless value.is_a?(String) + # type md5password is missleading, it is an plain password and not md5 hashed + when 'audit_command', 'runscript_short', 'autopassword', 'md5password', 'directory', 'string', 'strname', 'device', 'plugin_names' + # array + quote = true + raise 'Value need to be an string' unless value.is_a?(String) + when 'speed' + regex = %r{^\d+\W*(k|kb|m|mb)\/s$}i + when 'size64' + regex = %r{^(\d+(\.\d+)?)\W*(k|kb|m|mb|g|gb)$}i + when 'time' + regex = %r{^(\d+|(\d+\W+(seconds|sec|s|minutes|min|hours|h|days|d|weeks|w|months|m|quarters|q|years|y)\W*)+)$}i + when 'boolean', 'bit' + value_in_array = %w[yes no on off true false] + when 'address' + raise 'Value need to be an string' unless value.is_a?(String) + # validate net-address for domain name or ip + regex_hostname = %r{^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$}i + raise 'Value needs to be an ip or host address' unless value =~ Resolv::IPv4::Regex or value =~ Resolv::IPv6::Regex or value =~ Regexp.compile(regex_hostname) + when 'addresses' + hash_separator = ' = ' + raise 'Please specify as Hash' unless value.is_a?(Hash) + when 'include_exclude_item', 'runscript', 'hash' + raise 'Please specify as Hash' unless value.is_a?(Hash) + when 'backup_level' + value_in_array = %w[full incremental differential virtualfull initcatalog catalog volumetocatalog disktocatalog] + when 'io_direction' + value_in_array = %w[in out both] + when 'action_on_purge' + value_in_array = %w[truncate] + when 'encryption_cipher' + value_in_array = %w[aes128 aes192 aes256 camellia128 camellia192 camellia256 aes128hmacsha1 aes256hmacsha1 blowfish] + when 'auth_type' + value_in_array = %w[clear md5] + when 'auth_protocol_type', 'protocol_type' + value_in_array = %w[native ndmp] + when 'pooltype' + value_in_array = %w[backup archive cloned migration copy save scratch] + when 'label' + value_in_array = %w[ansi ibm bareos] + when 'migration_type' + value_in_array = %w[smallestvolume oldestvolume client volume job sqlquery pooloccupancy pooltime pooluncopiedjobs] + when 'job_type' + value_in_array = %w[backup restore verify admin migrate copy consolidate] + when 'replace_option' + value_in_array = %w[always ifnewer ifolder never] + when 'device_type' + value_in_array = %w[tape file fifo gfapi rados] + when 'compression_algorithm' + value_in_array = %w[gzip lzo lzfast lz4 lz4hc] + else + raise "Invalid setting type '#{type}'" + end + + unless value_in_array.nil? + raise "Value '#{value}' needs to be one of #{value_in_array.inspect}" unless value_in_array.include? value.to_s.downcase + end + unless regex.nil? + raise "Value '#{value}' does not match regex #{regex}" unless value =~ Regexp.compile(regex) + end + + if value.is_a?(Hash) + final_settings.push "#{indent}#{directive}#{hash_separator}{" + value.each do |k, v| + type_n = 'string_noquote' + type_n = "#{type_n}_list" if v.is_a?(Array) + # use same type again: + type_n = type if v.is_a?(Hash) + final_settings.push function_bareos_settings([[v, k, type_n, false, "#{indent} "]]) + end + final_settings.push "#{indent}}" + else + if quote + # value = value.gsub(/(")/, '\"') + value = "\"#{value}\"" + end + final_settings.push "#{indent}#{directive} = #{value}" + end + end + rescue => error + raise Puppet::ParseError, "bareos_settings(): #{setting.inspect}: #{error}." + end + end + + return final_settings.join "\n" + + end +end diff --git a/spec/functions/bareos_bareos_settings_spec.rb b/spec/functions/bareos_bareos_settings_spec.rb new file mode 100644 index 00000000..0d7fa80d --- /dev/null +++ b/spec/functions/bareos_bareos_settings_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'bareos::bareos_settings' do + # without knowing details about the implementation, this is the only test + # case that we can autogenerate. You should add more examples below! + it { is_expected.not_to eq(nil) } + +################################# +# Below are some example test cases. You may uncomment and modify them to match +# your needs. Notice that they all expect the base error class of `StandardError`. +# This is because the autogenerated function uses an untyped array for parameters +# and relies on your implementation to do the validation. As you convert your +# function to proper dispatches and typed signatures, you should change the +# expected error of the argument validation examples to `ArgumentError`. +# +# Other error types you might encounter include +# +# * StandardError +# * ArgumentError +# * Puppet::ParseError +# +# Read more about writing function unit tests at https://rspec-puppet.com/documentation/functions/ +# +# it 'raises an error if called with no argument' do +# is_expected.to run.with_params.and_raise_error(StandardError) +# end +# +# it 'raises an error if there is more than 1 arguments' do +# is_expected.to run.with_params({ 'foo' => 1 }, 'bar' => 2).and_raise_error(StandardError) +# end +# +# it 'raises an error if argument is not the proper type' do +# is_expected.to run.with_params('foo').and_raise_error(StandardError) +# end +# +# it 'returns the proper output' do +# is_expected.to run.with_params(123).and_return('the expected output') +# end +################################# + +end