New variable scoping question regarding defines calling defines.

383 views
Skip to first unread message

Trevor Vaughan

unread,
Dec 26, 2011, 8:56:26 AM12/26/11
to puppet...@googlegroups.com
I just ran into an interesting scenario where I didn't know how to
scope my variables and I'd just like to share for the crowd.

Suppose you have two modules 'foo' and 'bar'. You also have two
defines, 'foo::do_stuff' and 'bar::more_stuff'.

define foo::do_stuff (
$var1 = 'a',
$var2 = 'b'
) {
bar::more_stuff { 'test': }
}

define bar::more_stuff (
$optional_var = 'ignore'
) {
file { '/tmp/test':
content => template('bar/random.erb')
}

+++ random.erb +++

var1 = <%= var1 %>
var2 = <%= var2 %>

So, here, puppet complains about the scope of var1 and var2 but what
should the correct scope be? foo::do_stuff::var1, etc...? But how does
that work with multiple define calls to foo::do_stuff?

This, of course, can be avoided by putting the template under
foo/templates and forcing the passage of content to bar::more_stuff
but I'm not quite sure *why* this isn't supposed to work and what to
do about it with the notice that 2.8 will force the scoping of all
variables.

Thanks,

Trevor

--
Trevor Vaughan
Vice President, Onyx Point, Inc
(410) 541-6699
tvau...@onyxpoint.com

-- This account not approved for unencrypted proprietary information --

Aaron Grewell

unread,
Dec 27, 2011, 11:40:16 AM12/27/11
to puppet...@googlegroups.com
It's an interesting question, but I wouldn't want to structure my
modules that way. There are two methods of getting data into a define
that are guaranteed to work: passing variables and file retrieval
(extlookup/hiera). Especially given the changes being made to scoping
anything else is fraught with peril.

> --
> You received this message because you are subscribed to the Google Groups "Puppet Users" group.
> To post to this group, send email to puppet...@googlegroups.com.
> To unsubscribe from this group, send email to puppet-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
>

Trevor Vaughan

unread,
Dec 27, 2011, 2:21:36 PM12/27/11
to puppet...@googlegroups.com
There are actually pretty good reasons for doing it if you have a
fully modular setup.

For example:

Web Server module define -> Firewall code define -> ERB using higher
level variables.

There's no reason to stuff everything into a big data store when you
can easily pass it down. *But* if you try to use the top level
variable in the second define call ERB, then you've got issues.

I feel that this needs to be either forbidden (break the compile) or
allowed. But we'd need to know how to allow it.

Trevor

Aaron Grewell

unread,
Dec 27, 2011, 4:01:08 PM12/27/11
to puppet...@googlegroups.com

If you were actually passing the variable, yes. But you're not, you're expecting to reach into a non-class (essentially a grab-bag of resources) and extract data as though it were a class. It isn't and AFAIK you can't. You'll have to put the data in an actual class and address it from there.

Trevor Vaughan

unread,
Dec 27, 2011, 4:24:49 PM12/27/11
to puppet...@googlegroups.com
In that case, it should probably just fail instead of working (and
yes, it works).

Trevor

Aaron Grewell

unread,
Dec 27, 2011, 4:37:30 PM12/27/11
to puppet...@googlegroups.com
Yeah, I'd file a bug against that. There may be other considerations,
but unless there's a really good reason for the current behavior I
would expect it to throw an error.

Aaron Grewell

unread,
Dec 27, 2011, 4:46:30 PM12/27/11
to puppet...@googlegroups.com
Hmm, I just thought of this. Normally when referencing an instance of
a define you would use this syntax (note the caps):

Foo::Do_stuff['name']

Did you try:
Foo::Do_stuff['name']::var1

Trevor Vaughan

unread,
Dec 28, 2011, 9:08:16 AM12/28/11
to puppet...@googlegroups.com
I didn't. Seems odd but it might work.

Unfortunately, there's not really a way to know what 'name' would be
from the lower level define unless you were sure to call it with the
same name.

If you did that, you could use Foo::Do_stuff[$name]::var1 but I don't
really see another way of doing it.

Probably a bug.

Trevor

Trevor Vaughan

unread,
Dec 28, 2011, 9:18:32 AM12/28/11
to puppet...@googlegroups.com
Just tried this with no success.

I'm guessing that there's no way to know the calling scope.

Filed as bug 11584 even though these will all be compile failures as
of 2.8 (in theory).

Trevor

Ryan Coleman

unread,
Dec 28, 2011, 9:16:37 PM12/28/11
to puppet...@googlegroups.com


On Monday, December 26, 2011 5:56:26 AM UTC-8, Trevor Vaughan wrote:
I just ran into an interesting scenario where I didn't know how to
scope my variables and I'd just like to share for the crowd.

Suppose you have two modules 'foo' and 'bar'. You also have two
defines, 'foo::do_stuff' and 'bar::more_stuff'.

define foo::do_stuff (
  $var1 = 'a',
  $var2 = 'b'
) {
  bar::more_stuff { 'test': }
}

define bar::more_stuff (
  $optional_var = 'ignore'
) {
  file { '/tmp/test':
    content => template('bar/random.erb')
}

+++ random.erb +++

var1 = <%= var1 %>
var2 = <%= var2 %>

Have you tried this in your template?

<%= scope.lookupvar('foo::do_stuff::var1') %>

That should let you refer directly to the variable in that define, if I understand your setup correctly.

Trevor Vaughan

unread,
Dec 29, 2011, 8:53:58 AM12/29/11
to puppet...@googlegroups.com, Ryan Coleman
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The issue is that, should you call that define more than once, there's no way for Puppet to know which one to use unless it walks directly up the call
stack first.

Trevor

- --
Trevor Vaughan
Vice President, Onyx Point, Inc.
email: tvau...@onyxpoint.com
phone: 410-541-ONYX (6699)
pgp: 0x6C701E94

- -- This account not approved for unencrypted sensitive information --
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iQEcBAEBAgAGBQJO/HDxAAoJECNCGV1OLcypqScIAIlaCSNBRncSh4/1zGXyuvX5
CA35+lpr4TaQ8JweGltLmY0Ceb3RQcLyiqXdna3pZ1+kLNiKnrlysaRk6/e91zO7
0ngbhMGbOJLK0TyHFPq+5m+VjB0DvEvCaNRYIabQZWOwVKRLCpQYaFOoQPLyZ3f2
JX3YsvdhqhreVxqFKv7SlStc1cLxSoh8+TjWTwxQsa9Sq6Ff9P+iY+zTyHbZU7IP
opBLbg1uIS1xIYSYILZKtkDvQjAVfY8oYvmslz0MXKyS6TTZMVYGs8F8zJUZSpC8
lO8LEAyLtXsPIAGKNevfKpka3KxZ2wQ7mM70ydK3ShPEYe77V9K/oXBGeg2dh7E=
=/Fg0
-----END PGP SIGNATURE-----

tvaughan.vcf

jcbollinger

unread,
Jan 3, 2012, 10:12:38 AM1/3/12
to Puppet Users


On Dec 26 2011, 7:56 am, Trevor Vaughan <tvaug...@onyxpoint.com>
wrote:
Definitions are not equivalent to macros. Among other things, the
variables a definition declares are not added to the scope from which
it is instantiated, which is to say that definition instances
establish their own variable scopes.

Templates resolve variables from the scope in which the template()
function is called. The var1 and var2 are not local to that scope in
your example (see above), and that's why you get a scope warning.

Or did you mean you don't understand why dynamic scoping is being
removed? The basic reason seems to be that those making such
decisions judged that it causes more problems than it solves, and that
there was nothing that could be done with dynamic scoping that could
not also be done by other means. Indeed, I am convinced that a
significant reason for the introduction of parameterized classes was
to make that so.

As for you current case, I think the best solution is indeed to add
var1 and var2 as parameters to bar::more_stuff. They are de facto
parameters anyway, by virtue of the template's (dynamic) use of them,
so putting them in the parameter list makes things clearer (and thus
more maintainable). It also gives you more freedom in how you use the
definition. In other words, there is plenty of upside.


John



>
> Thanks,
>
> Trevor
>
> --
> Trevor Vaughan
> Vice President, Onyx Point, Inc
> (410) 541-6699
> tvaug...@onyxpoint.com

Trevor Vaughan

unread,
Jan 3, 2012, 12:14:38 PM1/3/12
to puppet...@googlegroups.com
Oh, I'm completely happy with the new scoping scheme and have worked
around any issues.

I just think that this should be a failure case since it is currently
(and probably has always been) something that shouldn't be done but
happened to previously work.

Trevor

> --
> You received this message because you are subscribed to the Google Groups "Puppet Users" group.
> To post to this group, send email to puppet...@googlegroups.com.
> To unsubscribe from this group, send email to puppet-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
>

--

Trevor Vaughan
Vice President, Onyx Point, Inc
(410) 541-6699

tvau...@onyxpoint.com

Reply all
Reply to author
Forward
0 new messages