Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -1368,6 +1368,17 @@ The following values will fail, causing compilation to abort:
~~~


#### `validate_legacy`

Validates a value against both a specified type and a deprecated validation function. Silently passes if both pass, errors if one validation passes and the other does not, fails if both validations return false.
Arguments include the type to check the value against, the full name of the previous validation function, the value itself to be checked, and an unspecified amount of arguments needed for the previous validation function.

Example:

~~~
validate_legacy("Optional[String]", "validate_re", "Value to be validated", ["."])
~~~

#### `validate_numeric`

Validates that the first argument is a numeric value (or an array of numeric values). Aborts catalog compilation if any of the checks fail.
Expand Down
54 changes: 54 additions & 0 deletions lib/puppet/functions/validate_legacy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Puppet::Functions.create_function(:validate_legacy, Puppet::Functions::InternalFunction) do
# The function checks a value against both the target_type (new) and the previous_validation function (old).

dispatch :validate_legacy do
param 'Type', :target_type
param 'String', :previous_validation
param 'NotUndef', :value
optional_param 'Any', :args
end
dispatch :validate_legacy_s do
scope_param
param 'String', :type_string
param 'String', :previous_validation
param 'NotUndef', :value
optional_repeated_param 'Any', :args
end

def validate_legacy_s(scope, type_string, *args)
t = Puppet::Pops::Types::TypeParser.new.parse(type_string, scope)
validate_legacy(t, *args)
end

def validate_legacy(target_type, previous_validation, value, *prev_args)
if assert_type(target_type, value)
if previous_validation(previous_validation, value, *prev_args)
# Silently passes
else
Puppet.warn("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(previous_validation, target_type, inferred_type)
if previous_validation(previous_validation, value, *prev_args)
Puppet.warn(error_msg)
else
call_function('fail', error_msg)
end
end
end

def previous_validation(previous_validation, value, *prev_args)
# Call the previous validation function and catch any errors. Return true if no errors are thrown.
begin
call_function(previous_validation, value, *prev_args)
true
rescue Puppet::ParseError
false
end
end

def assert_type(type, value)
Puppet::Pops::Types::TypeCalculator.instance?(type, value)
end
end
39 changes: 39 additions & 0 deletions spec/classes/validate_legacy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'spec_helper'

if Puppet.version.to_f >= 4.0
# validate_legacy requires a proper scope to run, so we have to trigger a true compilation here,
# instead of being able to leverage the function test group.
describe 'test::validate_legacy', type: :class do

describe 'validate_legacy passes assertion of type but not previous validation' do
let(:params) {{ type: "Optional[Integer]", prev_validation: "validate_re", value: 5, previous_arg1: ["^\\d+$", ""] }}
it {
Puppet.expects(:warn).with(includes('Accepting previously invalid value for target_type'))
is_expected.to compile
}
end

describe 'validate_legacy passes assertion of type and previous validation' do
let(:params) {{ type: "Optional[String]", prev_validation: "validate_re", value: "5", previous_arg1: ["."] }}
it { is_expected.to compile }
end

describe 'validate_legacy fails assertion of type and passes previous validation' do
let(:params) {{ type: "Optional[Integer]", prev_validation: "validate_re", value: "5", previous_arg1: ["."] }}
it {
Puppet.expects(:warn).with(includes('expected'))
is_expected.to compile
}
end

describe 'validate_legacy fails assertion and fails previous validation' do
let(:params) {{ type: "Optional[Integer]", prev_validation: "validate_re", value: "5", previous_arg1: ["thisisnotright"] }}
it { is_expected.to compile.and_raise_error(/Error while evaluating a Function Call, \w* expected an \w* value, got \w*/) }
end

describe 'validate_legacy works with multi-argument validate_ functions' do
let(:params) {{ type: "Integer", prev_validation: "validate_integer", value: 10, previous_arg1: 100, previous_arg2: 0 }}
it { is_expected.to compile }
end
end
end
18 changes: 18 additions & 0 deletions spec/fixtures/test/manifests/validate_legacy.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Class to test stdlib validate_legacy function

class test::validate_legacy(
$type,
$prev_validation,
$value,
$previous_arg1,
$previous_arg2 = undef,
) {

if $previous_arg2 == undef {
validate_legacy( $type, $prev_validation, $value, $previous_arg1 )
} else {
validate_legacy( $type, $prev_validation, $value, $previous_arg1, $previous_arg2 )
}
notice("Success")

}