Re: [Puppet Users] ERB strangness, or ruby/puppet internals I don''t understand

Thomas Bellman
2011-04-20T11:34:49Z

On 2011-04-15 21:10, Clay Caviness wrote:

> Let''s say I have a very simple template
> template.erb:
> <% if not has_variable?("foobar") then foobar =
"undefined" end -%>
> foobar: <%= foobar %>
> class: <%= foobar.class %>
>
> And a basic manifest:
> template.pp:
> $mytemp = template(''template.erb'')
> notice($mytemp)
>
> And then I apply the manifest, with an undefined foobar (no foobar fact):
> $ puppet apply ~/template.pp
> notice: Scope(Class[main]): foobar: undefined
> class: String
>
> notice: Finished catalog run in 0.01 seconds
>
> Looking good. So now I apply the manifest, but with a defined value
> for foobar (via the FACTER_FOOBAR environment variable):
> $ FACTER_FOOBAR=''foo'' puppet apply ~/template.pp
> notice: Scope(Class[main]): foobar:
> class: NilClass
>
> notice: Finished catalog run in 0.01 seconds
>
> Er, what? How on earth did foobar go from a String to NilClass? I
> can''t fathom how this is expected, or correct...

This happens because the Puppet variables are not exposed to ERB
as real Ruby variables.  Instead, Puppet uses some magic to catch
references to non-existing variables.  When the Ruby compiler sees
that you are assigning to foobar in your code, *anywhere* in your
code, it will create that variable for you, regardless of whether
the assignment is actually executed or not.  Since the variable now
exists, that will shadow Puppet''s magic.

That was at least what I found out when I investigated this when
running 0.24.something, and I don''t *think* they have changed how
Puppet variables are exposed to ERB since then.


> The reason I was doing this sort of thing is to give a possibly
> missing fact a default value. I ended up using a second variable, like
> this:
> <% foo = has_variable?("foobar") ? foobar.to_s :
"false" -%>

That is probably the best workaround.


	/Bellman