Skip to content

Commit

Permalink
Modernise fqdn_rotate function
Browse files Browse the repository at this point in the history
Convert the function to the modern function API as a namespaced function
and use the `networking` fact instead of legacy facts.

A non-namespaced shim is also created (but marked deprecated),
to preserve compatibility.

Fixes #1381
  • Loading branch information
alexjfisher committed Sep 15, 2023
1 parent 1e3884d commit cc0454e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 66 deletions.
14 changes: 14 additions & 0 deletions lib/puppet/functions/fqdn_rotate.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# THIS FILE WAS GENERATED BY `rake regenerate_unamespaced_shims`

# @summary DEPRECATED. Use the namespaced function [`stdlib::fqdn_rotate`](#stdlibfqdn_rotate) instead.
Puppet::Functions.create_function(:fqdn_rotate) do
dispatch :deprecation_gen do
repeated_param 'Any', :args
end
def deprecation_gen(*args)
call_function('deprecation', 'fqdn_rotate', 'This function is deprecated, please use stdlib::fqdn_rotate instead.', false)
call_function('stdlib::fqdn_rotate', *args)
end
end
66 changes: 66 additions & 0 deletions lib/puppet/functions/stdlib/fqdn_rotate.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# frozen_string_literal: true

# @summary Rotates an array or string a random number of times, combining the `fqdn` fact and an optional seed for repeatable randomness.
Puppet::Functions.create_function(:'stdlib::fqdn_rotate') do
# @param input
# The String you want rotated a random number of times
# @param seeds
# One of more values to use as a custom seed. These will be combined with the host's FQDN
#
# @return [String] Returns the rotated String
#
# @example Rotating a String
# stdlib::fqdn_rotate('abcd')
# @example Using a custom seed
# stdlib::fqdn_rotate('abcd', 'custom seed')
dispatch :fqdn_rotate_string do
param 'String', :input
optional_repeated_param 'Variant[Integer,String]', :seeds
return_type 'String'
end

# @param input
# The Array you want rotated a random number of times
# @param seeds
# One of more values to use as a custom seed. These will be combined with the host's FQDN
#
# @return [String] Returns the rotated Array
#
# @example Rotating an Array
# stdlib::fqdn_rotate(['a', 'b', 'c', 'd'])
# @example Using custom seeds
# stdlib::fqdn_rotate([1, 2, 3], 'custom', 'seed', 1)
dispatch :fqdn_rotate_array do
param 'Array', :input
optional_repeated_param 'Variant[Integer,String]', :seeds
return_type 'Array'
end

def fqdn_rotate_array(input, *seeds)
# Check whether it makes sense to rotate ...
return input if input.size <= 1

result = input.clone

require 'digest/md5'
seed = Digest::MD5.hexdigest([fqdn_fact, seeds].join(':')).hex

offset = Puppet::Util.deterministic_rand(seed, result.size).to_i

offset.times do
result.push result.shift
end

result
end

def fqdn_rotate_string(input, *seeds)
fqdn_rotate_array(input.chars, seeds).join
end

private

def fqdn_fact
closure_scope['facts']['networking']['fqdn']
end
end
59 changes: 0 additions & 59 deletions lib/puppet/parser/functions/fqdn_rotate.rb

This file was deleted.

12 changes: 5 additions & 7 deletions spec/functions/fqdn_rotate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

describe 'fqdn_rotate' do
it { is_expected.not_to be_nil }
it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
it { is_expected.to run.with_params(0).and_raise_error(Puppet::ParseError, %r{Requires either array or string to work with}) }
it { is_expected.to run.with_params({}).and_raise_error(Puppet::ParseError, %r{Requires either array or string to work with}) }
it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{expects at least 1 argument, got none}) }
it { is_expected.to run.with_params(0).and_raise_error(ArgumentError, %r{parameter 'input' expects a value of type String or Array, got Integer}) }
it { is_expected.to run.with_params({}).and_raise_error(ArgumentError, %r{parameter 'input' expects a value of type String or Array, got Hash}) }
it { is_expected.to run.with_params('').and_return('') }
it { is_expected.to run.with_params('a').and_return('a') }
it { is_expected.to run.with_params('ã').and_return('ã') }
Expand Down Expand Up @@ -48,8 +48,6 @@
end

it 'uses the Puppet::Util.deterministic_rand function' do
skip 'Puppet::Util#deterministic_rand not available' unless Puppet::Util.respond_to?(:deterministic_rand)

expect(Puppet::Util).to receive(:deterministic_rand).with(44_489_829_212_339_698_569_024_999_901_561_968_770, 4)
fqdn_rotate('asdf')
end
Expand All @@ -68,9 +66,9 @@ def fqdn_rotate(value, args = {})

# workaround not being able to use let(:facts) because some tests need
# multiple different hostnames in one context
allow(scope).to receive(:lookupvar).with('facts').and_return(host)
allow(subject.func.closure_scope).to receive(:[]).with('facts').and_return({ 'networking' => { 'fqdn' => host } })

function_args = [value] + extra
scope.function_fqdn_rotate(function_args)
scope.call_function('fqdn_rotate', function_args)
end
end

0 comments on commit cc0454e

Please sign in to comment.