-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite fqdn_rand_string() as a Puppet 4.x function #1343
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# frozen_string_literal: true | ||
|
||
# @summary | ||
# Generates a random alphanumeric string. Combining the `$fqdn` fact and an | ||
# optional seed for repeatable randomness. | ||
# | ||
# Optionally, you can specify a character set for the function (defaults to alphanumeric). | ||
Puppet::Functions.create_function(:fqdn_rand_string) do | ||
# @param length The length of the resulting string. | ||
# @param charset The character set to use. | ||
# @param The seed for repeatable randomness. | ||
# | ||
# @return [String] | ||
# | ||
# @example Example Usage: | ||
# fqdn_rand_string(10) | ||
# fqdn_rand_string(10, 'ABCDEF!@$%^') | ||
# fqdn_rand_string(10, '', 'custom seed') | ||
dispatch :fqdn_rand_string do | ||
param 'Integer[1]', :length | ||
optional_param 'String', :charset | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was it necessary to make this a breaking change? I have code that called the function like this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in #1367 |
||
optional_repeated_param 'Any', :seed | ||
end | ||
|
||
def fqdn_rand_string(length, charset = '', *seed) | ||
charset = charset.chars.to_a | ||
|
||
charset = (0..9).map { |i| i.to_s } + ('A'..'Z').to_a + ('a'..'z').to_a if charset.empty? | ||
|
||
rand_string = '' | ||
length.times do |current| | ||
rand_string += charset[call_function('fqdn_rand', charset.size, (seed + [current + 1]).join(':'))] | ||
end | ||
|
||
rand_string | ||
end | ||
end |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,68 +6,50 @@ | |
let(:default_charset) { %r{\A[a-zA-Z0-9]{100}\z} } | ||
|
||
it { is_expected.not_to eq(nil) } | ||
it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{wrong number of arguments}i) } | ||
it { is_expected.to run.with_params(0).and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params(1.5).and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params(-10).and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params('-10').and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params('string').and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params([]).and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params({}).and_raise_error(ArgumentError, %r{first argument must be a positive integer}) } | ||
it { is_expected.to run.with_params(1, 1).and_raise_error(ArgumentError, %r{second argument must be undef or a string}) } | ||
it { is_expected.to run.with_params(1, []).and_raise_error(ArgumentError, %r{second argument must be undef or a string}) } | ||
it { is_expected.to run.with_params(1, {}).and_raise_error(ArgumentError, %r{second argument must be undef or a string}) } | ||
it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{expects at least 1 argument, got none}i) } | ||
it { is_expected.to run.with_params(0).and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer\[1\] value, got Integer\[0, 0\]}) } | ||
it { is_expected.to run.with_params(1.5).and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer\ value, got Float}) } | ||
it { is_expected.to run.with_params(-10).and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer\[1\] value, got Integer\[-10, -10\]}) } | ||
it { is_expected.to run.with_params('-10').and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer\ value, got String}) } | ||
it { is_expected.to run.with_params('string').and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer\ value, got String}) } | ||
it { is_expected.to run.with_params([]).and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer value, got Array}) } | ||
it { is_expected.to run.with_params({}).and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer value, got Hash}) } | ||
it { is_expected.to run.with_params(1, 1).and_raise_error(ArgumentError, %r{parameter 'charset' expects a String value, got Integer}) } | ||
it { is_expected.to run.with_params(1, []).and_raise_error(ArgumentError, %r{parameter 'charset' expects a String value, got Array}) } | ||
it { is_expected.to run.with_params(1, {}).and_raise_error(ArgumentError, %r{parameter 'charset' expects a String value, got Hash}) } | ||
it { is_expected.to run.with_params('100').and_raise_error(ArgumentError, %r{parameter 'length' expects an Integer value, got String}) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
it { is_expected.to run.with_params(100, nil).and_raise_error(ArgumentError, %r{parameter 'charset' expects a String value, got Undef}) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might create a PR to revert this though. |
||
it { is_expected.to run.with_params(100).and_return(default_charset) } | ||
it { is_expected.to run.with_params('100').and_return(default_charset) } | ||
it { is_expected.to run.with_params(100, nil).and_return(default_charset) } | ||
it { is_expected.to run.with_params(100, '').and_return(default_charset) } | ||
it { is_expected.to run.with_params(100, 'a').and_return(%r{\Aa{100}\z}) } | ||
it { is_expected.to run.with_params(100, 'ab').and_return(%r{\A[ab]{100}\z}) } | ||
it { is_expected.to run.with_params(100, 'ãβ').and_return(%r{\A[ãβ]{100}\z}) } | ||
|
||
it "provides the same 'random' value on subsequent calls for the same host" do | ||
expect(fqdn_rand_string(10)).to eql(fqdn_rand_string(10)) | ||
end | ||
|
||
it 'considers the same host and same extra arguments to have the same random sequence' do | ||
first_random = fqdn_rand_string(10, extra_identifier: [1, 'same', 'host']) | ||
second_random = fqdn_rand_string(10, extra_identifier: [1, 'same', 'host']) | ||
|
||
expect(first_random).to eql(second_random) | ||
end | ||
|
||
it 'allows extra arguments to control the random value on a single host' do | ||
first_random = fqdn_rand_string(10, extra_identifier: [1, 'different', 'host']) | ||
second_different_random = fqdn_rand_string(10, extra_identifier: [2, 'different', 'host']) | ||
|
||
expect(first_random).not_to eql(second_different_random) | ||
end | ||
|
||
it 'returns different strings for different hosts' do | ||
val1 = fqdn_rand_string(10, host: 'first.host.com') | ||
val2 = fqdn_rand_string(10, host: 'second.host.com') | ||
|
||
expect(val1).not_to eql(val2) | ||
end | ||
context 'produce predictible and reproducible results' do | ||
before(:each) do | ||
if Gem::Version.new(Puppet::PUPPETVERSION) < Gem::Version.new('7.23.0') | ||
allow(scope).to receive(:lookupvar).with('::fqdn', {}).and_return(fqdn) | ||
else | ||
allow(scope).to receive(:lookupvar).with('facts', {}).and_return({ 'networking' => { 'fqdn' => fqdn } }) | ||
end | ||
end | ||
|
||
def fqdn_rand_string(max, args = {}) | ||
host = args[:host] || '127.0.0.1' | ||
charset = args[:charset] | ||
extra = args[:extra_identifier] || [] | ||
context 'on a node named example.com' do | ||
let(:fqdn) { 'example.com' } | ||
|
||
# workaround not being able to use let(:facts) because some tests need | ||
# multiple different hostnames in one context | ||
if Gem::Version.new(Puppet::PUPPETVERSION) < Gem::Version.new('7.23.0') | ||
allow(scope).to receive(:lookupvar).with('::fqdn', {}).and_return(host) | ||
else | ||
allow(scope).to receive(:lookupvar).with('facts', {}).and_return({ 'networking' => { 'fqdn' => host } }) | ||
it { is_expected.to run.with_params(5).and_return('Pw5NP') } | ||
it { is_expected.to run.with_params(10, 'abcd').and_return('cdadaaacaa') } | ||
it { is_expected.to run.with_params(20, '', 'custom seed').and_return('3QKQHP4wmEObY3a6hkeg') } | ||
it { is_expected.to run.with_params(20, '', 'custom seed', 1, 'extra').and_return('OA19SVDoc3QPY5NlSQ28') } | ||
end | ||
|
||
function_args = [max] | ||
if args.key?(:charset) || !extra.empty? | ||
function_args << charset | ||
context 'on a node named desktop-fln40kq.lan' do | ||
let(:fqdn) { 'desktop-fln40kq.lan' } | ||
|
||
it { is_expected.to run.with_params(5).and_return('bgQsB') } | ||
it { is_expected.to run.with_params(10, 'abcd').and_return('bcdbcdacad') } | ||
it { is_expected.to run.with_params(20, '', 'custom seed').and_return('KaZsFlWkUo5SeA3gBEf0') } | ||
it { is_expected.to run.with_params(20, '', 'custom seed', 1, 'extra').and_return('dcAzn1e8AA7hhoLpxAD6') } | ||
end | ||
function_args += extra | ||
scope.function_fqdn_rand_string(function_args) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto re namespacing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it is the plan 😁 I am currently playing three-cushion billiards:
The above is pretty clean in my head but I guess I should dump this somewhere where we can track progress, see what is coming next and so on. I am really not good at this, and any suggestion is welcome!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack, feel free to close all comments related to this and we can deal with the general issue in #1346
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! I subscribed to the issue. Thanks!