Reputation: 4232
Context:
I have a puppet template that addresses the count
sub-component of the processors
fact when it is rendered. That fact exists on all of my clients.
The use case for the fact is in a template line that performs decimal math on it, e.g.: MyConfigVar=<%= 0.9 * @processors['count'] %>
in some .erb
file.
I want to:
What I've Tried:
First, I tried with sigils: <%= 0.9 * @processors[:count] %>
. If I mocked, with rspec-puppet, something like facts = { :processors => { :count => 10 } }
, my tests all passed. Manifest application didn't work; it had a "can't multiply nil
" error. Sigils apparently are out.
Then, I tried with stringy keys: <%= 0.9 * @processors['count'] %>
. My tests with the sigil (facts = { :processors => { :count => 10 } }
) weren't picked up, but my value was properly found and multiplied with facts = { :processors => { 'count' => 10 } }
. All tests then passed. However, manifest application failed with a Can't coerce String into Int
failure.
Then, I tried with stringy values. The template still read <%= 0.9 * @processors['count'].to_i %>
, and I tested both string and integer values, e.g.
let(:facts) { :processors => { 'count' => '10' } }
# tests with string value
let(:facts) { :processors => { 'count' => 10 } }
# tests with integer value
The tests all passed, but manifest application rendered 0.0
for the value of the fact.
Questions:
Two main questions:
rspec-puppet
or similar, mocking values in facter with production-representative types?Upvotes: 3
Views: 1393
Reputation: 5190
There's a few things at play here.
As Josh Souza says, older versions of Facter did not support hashes or arrays. So depending on the version of Puppet and Facter your using, I would check what the value of stringify_facts config.
If this is set to true (which it will be on older Puppet) then facts will not come out as hashes, they get cast to a string in your manifest, leading to a mashed up string with no separation (eg. modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1
). Note the count1
, that would have been :count => 1
in the original hash.
You can test this with the stringify_facts
setting in your spec_helper in rspec-puppet >= 2.2.
So there a number of legacy facts that aren't hashes that you can see if you run facter -p
:
$ facter -p | grep processor
processorcount => 8
processors => {"count"=>8, "speed"=>"2.5 GHz"}
sp_current_processor_speed => 2.5 GHz
sp_number_processors => 4
So I'd recommend using the $::processorcount
fact, which should be an integer because that's the value returned, but you could use to_i
to be sure in your .erb
template. I'm pretty sure it should always return an integer.
If you're feeling really brave, you can create a function to cast the value to a numeric and use that in your manifest (For example https://github.com/kwilczynski/puppet-functions/blob/master/lib/puppet/parser/functions/str2num.rb)
So you'd have code that looks like:
if (is_integer($::processorcount)) {
$processor_as_int = $::processorcount
} else {
$processor_as_int = str2num($::processorcount)
}
All in all, it's a bit messy, you can see why in Puppet 4 we have a much tighter typing system!
Upvotes: 2
Reputation: 406
For what it's worth, I did some investigation into your issue, and in my test bed the 'processors' fact, while a hash when running facter processors
, is actually a string once it makes its way into Puppet/templates and it lacks any separator (I.E. "modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1" is the raw value). I verified this by using '@processors.class' in my ruby template, as well as a few other tests to be sure. My testbed is running Puppet 3.8.3 and Facter 2.4.6, in case that affected things.
So the solutions I can propose are:
Use Facter directly within your template (Which is very non-puppety, but it works)
<%= Facter.value(:processors)['count'] %>
Use regex string parsing (I don't recommend this, as it's fragile and hacky, but it DOES do the trick)
[email protected]!(/physicalcount/,'physical').gsub!(/.*count([0-9])+.*/,'\1')
It's quite possible that in different versions of Puppet/Facter this isn't a problem, but hopefully this is enough to get you rolling in the right direction.
Upvotes: 2