(MODULES-1715) Add fqdn_rand string generators
This commit is contained in:
parent
14a02ea21e
commit
a82266c256
5 changed files with 262 additions and 0 deletions
|
@ -244,6 +244,23 @@ This function flattens any deeply nested arrays and returns a single flat array
|
|||
Returns the largest integer less than or equal to the argument.
|
||||
Takes a single numeric value as an argument. *Type*: rvalue
|
||||
|
||||
#### `fqdn_rand_string`
|
||||
|
||||
Generates a random alphanumeric string using an optionally-specified character set (default is alphanumeric), combining the `$fqdn` fact and an optional seed for repeatable randomness.
|
||||
|
||||
*Usage:*
|
||||
```
|
||||
fqdn_rand_string(LENGTH, [CHARSET], [SEED])
|
||||
```
|
||||
*Examples:*
|
||||
```
|
||||
fqdn_rand_string(10)
|
||||
fqdn_rand_string(10, 'ABCDEF!@#$%^')
|
||||
fqdn_rand_string(10, '', 'custom seed')
|
||||
```
|
||||
|
||||
*Type*: rvalue
|
||||
|
||||
#### `fqdn_rotate`
|
||||
|
||||
Rotates an array a random number of times based on a node's fqdn. *Type*: rvalue
|
||||
|
|
34
lib/puppet/parser/functions/fqdn_rand_string.rb
Normal file
34
lib/puppet/parser/functions/fqdn_rand_string.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
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.size == 0
|
||||
Puppet::Parser::Functions.function('is_integer')
|
||||
raise(ArgumentError, "fqdn_rand_base64(): first argument must be a positive integer") unless function_is_integer([args[0]]) and args[0].to_i > 0
|
||||
raise(ArgumentError, "fqdn_rand_base64(): second argument must be undef or a string") unless args[1].nil? or 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
|
||||
rand_string << charset[function_fqdn_rand([charset.size, (args + [current.to_s]).join(':')]).to_i]
|
||||
end
|
||||
|
||||
rand_string
|
||||
end
|
60
spec/acceptance/fqdn_rand_base64_spec.rb
Normal file
60
spec/acceptance/fqdn_rand_base64_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
#! /usr/bin/env ruby -S rspec
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'fqdn_rand_base64 function', :unless => unsupported_platforms.include?(fact('operatingsystem')) do
|
||||
describe 'success' do
|
||||
let(:facts_d) do
|
||||
if fact('is_pe', '--puppet') == "true"
|
||||
if fact('osfamily') =~ /windows/i
|
||||
if fact('kernelmajversion').to_f < 6.0
|
||||
'c:/documents and settings/all users/application data/puppetlabs/facter/facts.d'
|
||||
else
|
||||
'c:/programdata/puppetlabs/facter/facts.d'
|
||||
end
|
||||
else
|
||||
'/etc/puppetlabs/facter/facts.d'
|
||||
end
|
||||
else
|
||||
'/etc/facter/facts.d'
|
||||
end
|
||||
end
|
||||
after :each do
|
||||
shell("if [ -f '#{facts_d}/fqdn.txt' ] ; then rm '#{facts_d}/fqdn.txt' ; fi")
|
||||
end
|
||||
before :each do
|
||||
#no need to create on windows, pe creates by default
|
||||
if fact('osfamily') !~ /windows/i
|
||||
shell("mkdir -p '#{facts_d}'")
|
||||
end
|
||||
end
|
||||
it 'generates random base64 strings' do
|
||||
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
|
||||
pp = <<-eos
|
||||
$l = 10
|
||||
$o = fqdn_rand_base64($l)
|
||||
notice(inline_template('fqdn_rand_base64 is <%= @o.inspect %>'))
|
||||
eos
|
||||
|
||||
apply_manifest(pp, :catch_failures => true) do |r|
|
||||
expect(r.stdout).to match(/fqdn_rand_base64 is "8ySYp0dq0B"/)
|
||||
end
|
||||
end
|
||||
it 'generates random base64 strings with custom seeds' do
|
||||
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
|
||||
pp = <<-eos
|
||||
$l = 10
|
||||
$s = 'seed'
|
||||
$o = fqdn_rand_base64($l, $s)
|
||||
notice(inline_template('fqdn_rand_base64 is <%= @o.inspect %>'))
|
||||
eos
|
||||
|
||||
apply_manifest(pp, :catch_failures => true) do |r|
|
||||
expect(r.stdout).to match(/fqdn_rand_base64 is "6J2c4oMRUJ"/)
|
||||
end
|
||||
end
|
||||
end
|
||||
describe 'failure' do
|
||||
it 'handles improper argument counts'
|
||||
it 'handles non-numbers for length argument'
|
||||
end
|
||||
end
|
60
spec/acceptance/fqdn_rand_string_spec.rb
Normal file
60
spec/acceptance/fqdn_rand_string_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
#! /usr/bin/env ruby -S rspec
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'fqdn_rand_string function', :unless => unsupported_platforms.include?(fact('operatingsystem')) do
|
||||
describe 'success' do
|
||||
let(:facts_d) do
|
||||
if fact('is_pe', '--puppet') == "true"
|
||||
if fact('osfamily') =~ /windows/i
|
||||
if fact('kernelmajversion').to_f < 6.0
|
||||
'c:/documents and settings/all users/application data/puppetlabs/facter/facts.d'
|
||||
else
|
||||
'c:/programdata/puppetlabs/facter/facts.d'
|
||||
end
|
||||
else
|
||||
'/etc/puppetlabs/facter/facts.d'
|
||||
end
|
||||
else
|
||||
'/etc/facter/facts.d'
|
||||
end
|
||||
end
|
||||
after :each do
|
||||
shell("if [ -f '#{facts_d}/fqdn.txt' ] ; then rm '#{facts_d}/fqdn.txt' ; fi")
|
||||
end
|
||||
before :each do
|
||||
#no need to create on windows, pe creates by default
|
||||
if fact('osfamily') !~ /windows/i
|
||||
shell("mkdir -p '#{facts_d}'")
|
||||
end
|
||||
end
|
||||
it 'generates random alphanumeric strings' do
|
||||
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
|
||||
pp = <<-eos
|
||||
$l = 10
|
||||
$o = fqdn_rand_string($l)
|
||||
notice(inline_template('fqdn_rand_string is <%= @o.inspect %>'))
|
||||
eos
|
||||
|
||||
apply_manifest(pp, :catch_failures => true) do |r|
|
||||
expect(r.stdout).to match(/fqdn_rand_string is "7oDp0KOr1b"/)
|
||||
end
|
||||
end
|
||||
it 'generates random alphanumeric strings with custom seeds' do
|
||||
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
|
||||
pp = <<-eos
|
||||
$l = 10
|
||||
$s = 'seed'
|
||||
$o = fqdn_rand_string($l, $s)
|
||||
notice(inline_template('fqdn_rand_string is <%= @o.inspect %>'))
|
||||
eos
|
||||
|
||||
apply_manifest(pp, :catch_failures => true) do |r|
|
||||
expect(r.stdout).to match(/fqdn_rand_string is "3HS4mbuI3E"/)
|
||||
end
|
||||
end
|
||||
end
|
||||
describe 'failure' do
|
||||
it 'handles improper argument counts'
|
||||
it 'handles non-numbers for length argument'
|
||||
end
|
||||
end
|
91
spec/functions/fqdn_rand_string_spec.rb
Normal file
91
spec/functions/fqdn_rand_string_spec.rb
Normal file
|
@ -0,0 +1,91 @@
|
|||
#! /usr/bin/env ruby -S rspec
|
||||
require 'spec_helper'
|
||||
|
||||
describe "the fqdn_rand_string function" do
|
||||
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
|
||||
|
||||
it "should exist" do
|
||||
expect(Puppet::Parser::Functions.function("fqdn_rand_string")).to eq("function_fqdn_rand_string")
|
||||
end
|
||||
|
||||
it "should raise an ArgumentError if there is less than 1 argument" do
|
||||
expect { fqdn_rand_string() }.to( raise_error(ArgumentError, /wrong number of arguments/))
|
||||
end
|
||||
|
||||
it "should raise an ArgumentError if argument 1 isn't a positive integer" do
|
||||
expect { fqdn_rand_string(0) }.to( raise_error(ArgumentError, /first argument must be a positive integer/))
|
||||
expect { fqdn_rand_string(-1) }.to( raise_error(ArgumentError, /first argument must be a positive integer/))
|
||||
expect { fqdn_rand_string(0.5) }.to( raise_error(ArgumentError, /first argument must be a positive integer/))
|
||||
end
|
||||
|
||||
it "provides a valid alphanumeric string when no character set is provided" do
|
||||
length = 100
|
||||
string = %r{\A[a-zA-Z0-9]{#{length}}\z}
|
||||
expect(fqdn_rand_string(length).match(string)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "provides a valid alphanumeric string when an undef character set is provided" do
|
||||
length = 100
|
||||
string = %r{\A[a-zA-Z0-9]{#{length}}\z}
|
||||
expect(fqdn_rand_string(length, :charset => nil).match(string)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "provides a valid alphanumeric string when an empty character set is provided" do
|
||||
length = 100
|
||||
string = %r{\A[a-zA-Z0-9]{#{length}}\z}
|
||||
expect(fqdn_rand_string(length, :charset => '').match(string)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "uses a provided character set" do
|
||||
length = 100
|
||||
charset = '!@#$%^&*()-_=+'
|
||||
string = %r{\A[#{charset}]{#{length}}\z}
|
||||
expect(fqdn_rand_string(length, :charset => charset).match(string)).not_to eq(nil)
|
||||
end
|
||||
|
||||
it "provides a random string exactly as long as the given length" do
|
||||
expect(fqdn_rand_string(10).size).to eql(10)
|
||||
end
|
||||
|
||||
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 "should return 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
|
||||
|
||||
def fqdn_rand_string(max, args = {})
|
||||
host = args[:host] || '127.0.0.1'
|
||||
charset = args[:charset]
|
||||
extra = args[:extra_identifier] || []
|
||||
|
||||
scope = PuppetlabsSpec::PuppetInternals.scope
|
||||
scope.stubs(:[]).with("::fqdn").returns(host)
|
||||
scope.stubs(:lookupvar).with("::fqdn").returns(host)
|
||||
|
||||
function_args = [max]
|
||||
if args.has_key?(:charset) or !extra.empty?
|
||||
function_args << charset
|
||||
end
|
||||
function_args += extra
|
||||
scope.function_fqdn_rand_string(function_args)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue