Skip to content

Commit

Permalink
(MODULES-1738) Don't modify global seed in fqdn_rotate()
Browse files Browse the repository at this point in the history
As per puppetlabs/puppet@292233c, this leaves the global seed in a
deterministic state, which is bad. Puppet::Util.deterministic_rand()
exists to avoid running into this issue, but is only present starting in
Puppet 3.2.0.
  • Loading branch information
elyscape committed Feb 12, 2015
1 parent afc83ea commit 84f866f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
16 changes: 14 additions & 2 deletions lib/puppet/parser/functions/fqdn_rotate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,20 @@ module Puppet::Parser::Functions

elements = result.size

srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
rand(elements).times {
seed = Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex
# deterministic_rand() was added in Puppet 3.2.0; reimplement if necessary
if Puppet::Util.respond_to?(:deterministic_rand)
offset = Puppet::Util.deterministic_rand(seed, elements).to_i
else
if defined?(Random) == 'constant' && Random.class == Class
offset = Random.new(seed).rand(elements)
else
srand(seed)
offset = rand(elements)
srand()
end
end
offset.times {
result.push result.shift
}

Expand Down
17 changes: 17 additions & 0 deletions spec/functions/fqdn_rotate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,21 @@ class AlsoString < String
result = scope.function_fqdn_rotate([value])
result.size.should(eq(4))
end

it "should use the Puppet::Util.deterministic_rand function if available" do
scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
if Puppet::Util.respond_to?(:deterministic_rand)
Puppet::Util.expects(:deterministic_rand).with(113646079810780526294648115052177588845,4)
end
scope.function_fqdn_rotate(["asdf"])
end

it "should not leave the global seed in a deterministic state" do
scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice
scope.function_fqdn_rotate(["asdf"])
rand1 = rand()
scope.function_fqdn_rotate(["asdf"])
rand2 = rand()
expect(rand1).not_to eql(rand2)
end
end

0 comments on commit 84f866f

Please sign in to comment.