Puppet 3 scoping question

47 views
Skip to first unread message

w...@stanford.edu

unread,
Nov 6, 2014, 9:30:16 PM11/6/14
to puppet...@googlegroups.com
In puppet 2.7 we use the following construct.

define some::fun(
  ensure => present,
  sname => 'some.server.com'
) {
  include some::fun_setup
  # Template uses sname
  file {"/path/$name":
    content => template("${name}.erb"),
  }
}

class some::fun_setup {
  file{"/etc/ssl/certs/${sname}":
    source => "puppet:///modules/some-files/${sname}.ca.pem"
  }
}

The reference to sname in some::fun_setup does not work in puppet 3.  Not surprising given the scoping changes.  The problem is I am not sure how to reference sname defined in the resource from the class some::fun_setup.  In reading the documentation I think something like $some::fun::sname should work, but it doesn't.  What is the correct way to reference sname from some::fun_setup?

The goal is to be able to have manifests that use some::fun as follows:


  some::fun{'fragment1': ensure => present}

  some::fun{'fragment2': ensure => present}
  ...

The fragments are unique, but the ca cert only needs to be installed once.

Thanks in advance,

Bill

Walid

unread,
Nov 7, 2014, 1:38:00 AM11/7/14
to puppet...@googlegroups.com
it would be some::fun_setup::sname or more specifically :: some::fun_setup::sname or $:: some::fun_setup::sname

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/affc1a19-64fa-4393-8b17-2b5773eec1ab%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

w...@stanford.edu

unread,
Nov 7, 2014, 2:43:03 AM11/7/14
to puppet...@googlegroups.com
But that doesn't make sense to me and in my test didn't work.  What your syntax does is to reference the variable sname in the class from the class.  That is, the class would become:

class some::fun_setup {
  file{"/etc/ssl/certs/${::some::fun_setup::sname}":
    source => "puppet:///modules/some-files/${::some::fun_setup::sname}.ca.pem"
  }
}

But, what I am attempting to do is to pull the value of the sname parameter from the resource type some::fun.

Bill

jcbollinger

unread,
Nov 7, 2014, 9:40:14 AM11/7/14
to puppet...@googlegroups.com


On Thursday, November 6, 2014 8:30:16 PM UTC-6, w...@stanford.edu wrote:
In puppet 2.7 we use the following construct.

define some::fun(
  ensure => present,
  sname => 'some.server.com'


This isn't the source of your problem, but do be aware that setting default parameter values via '=>' is deprecated.  You should use '=' instead (which works in Puppet 2.7, too).

 
) {
  include some::fun_setup
  # Template uses sname
  file {"/path/$name":
    content => template("${name}.erb"),
  }
}

class some::fun_setup {
  file{"/etc/ssl/certs/${sname}":
    source => "puppet:///modules/some-files/${sname}.ca.pem"
  }
}

The reference to sname in some::fun_setup does not work in puppet 3.


No, it wouldn't.  You are relying on dynamic scoping, which was dropped in Puppet 3.

 
  Not surprising given the scoping changes.  The problem is I am not sure how to reference sname defined in the resource from the class some::fun_setup.


You cannot safely do this, and it is anyway not sensible.  Indeed, it might not do quite what you think it does even in Puppet 2.  Consider that if you make some::fun a defined type instead of a class, then you are explicitly providing for the possibility that multiple instances may be declared.  Consider also that if you make $sname a parameter of type some::fun, then you are providing for it to have different values for different instances.  So what do you suppose will happen in Puppet 2.7 if you do this:

some::fun { 'f1': sname => 'server1.my.com' }
some
::fun { 'f2': sname => 'server2.my.com' }

?  Hint: classes are singletons; you get at most one instance of any given class, no matter how many times a declaration of that class is evaluated.

 
  In reading the documentation I think something like $some::fun::sname should work, but it doesn't.


That form works if some::fun is a class, but you cannot access resource parameters that way (defined type instances are resources).
 
  What is the correct way to reference sname from some::fun_setup?

The goal is to be able to have manifests that use some::fun as follows:


  some::fun{'fragment1': ensure => present}

  some::fun{'fragment2': ensure => present}
  ...

Your design is flawed.  You need to rethink it.  Some of your options are
  • make some::fun_setup a defined type, and pass $sname as a parameter (this will break if you have multiple some::fun instances with the same $sname)
  • externalize $sname, remove it from some::fun's parameter list, and have class some::fun_setup load it via Hiera (this does not support different some::fun instances relying on different $sname, but that's not actually working for you now)
If you need to support multiple some::fun_instances, with some but not all sharing any given $sname (i.e. a many to many relationship), then you're going to need to make deeper changes.


John

Felix Frank

unread,
Nov 7, 2014, 12:39:53 PM11/7/14
to puppet...@googlegroups.com
On 11/07/2014 03:40 PM, jcbollinger wrote:
> If you need to support multiple some::fun_instances, with some but not
> all sharing any given $sname (i.e. a many to many relationship), then
> you're going to need to make deeper changes.

Yeah.

FWIW, this is the one use case that worries me most when thinking about
patterns to eliminate the defined() horror.

define something::specific($group) {
file { "/things/$group/$name": }
if !defined( File["/things/$group"] ) {
file { "/things/$group": ensure => directory }
}
}

I.e., a defined type of which some but not all instances depend on a
shared resource. Constraints could ensure a consistent catalog, but how
can the dependency be automatically satisfied without defined() or
ensure_resource()?

I'm toying with ideas for allowing multiple declarations of the same
resource. That will pose other exiting issues, but might be the least
painful way.

Sorry for derailing, I just wanted to note that here ere I forget.

Bill MacAllister

unread,
Nov 7, 2014, 1:40:26 PM11/7/14
to puppet...@googlegroups.com


--On Friday, November 07, 2014 06:39:41 PM +0100 Felix Frank <felix...@alumni.tu-berlin.de> wrote:

> On 11/07/2014 03:40 PM, jcbollinger wrote:
>> If you need to support multiple some::fun_instances, with some but not
>> all sharing any given $sname (i.e. a many to many relationship), then
>> you're going to need to make deeper changes.

The more I think about what I implemented the less I like it. The goal
had been to allow the pattern:

fragment{'one': ensure => present}
fragment{'two': ensure => present}

But I will need to change the pattern to:

setup:{'server': ensure => present}
fragment{'one': ensure => present}
fragment{'two': ensure => present}

> Yeah.
>
> FWIW, this is the one use case that worries me most when thinking about
> patterns to eliminate the defined() horror.
>
> define something::specific($group) {
> file { "/things/$group/$name": }
> if !defined( File["/things/$group"] ) {
> file { "/things/$group": ensure => directory }
> }
> }

Yes, I like that. Let me know when I can use it. ;-)

> I.e., a defined type of which some but not all instances depend on a
> shared resource. Constraints could ensure a consistent catalog, but how
> can the dependency be automatically satisfied without defined() or
> ensure_resource()?
>
> I'm toying with ideas for allowing multiple declarations of the same
> resource. That will pose other exiting issues, but might be the least
> painful way.
>
> Sorry for derailing, I just wanted to note that here ere I forget.

Not a problem. Thanks for thinking about it.

Bill

--

Bill MacAllister
System Programmer, Stanford University


Felix Frank

unread,
Nov 7, 2014, 1:57:05 PM11/7/14
to puppet...@googlegroups.com
On 11/07/2014 07:40 PM, Bill MacAllister wrote:
>>
>> define something::specific($group) {
>> file { "/things/$group/$name": }
>> if !defined( File["/things/$group"] ) {
>> file { "/things/$group": ensure => directory }
>> }
>> }
>
> Yes, I like that. Let me know when I can use it. ;-)

Well, you *can* do this right now. As long as this is the only query for
this resource, I would go so far as to claim that this is one of the few
clean use cases for defined(). Just make sure to steer clear in any
other situation.

jcbollinger

unread,
Nov 10, 2014, 9:29:43 AM11/10/14
to puppet...@googlegroups.com


On Friday, November 7, 2014 11:39:53 AM UTC-6, Felix.Frank wrote:
On 11/07/2014 03:40 PM, jcbollinger wrote:
> If you need to support multiple some::fun_instances, with some but not
> all sharing any given $sname (i.e. a many to many relationship), then
> you're going to need to make deeper changes.

Yeah.

FWIW, this is the one use case that worries me most when thinking about
patterns to eliminate the defined() horror.

define something::specific($group) {
    file { "/things/$group/$name": }
    if !defined( File["/things/$group"] ) {
        file { "/things/$group": ensure => directory }
    }
}

I.e., a defined type of which some but not all instances depend on a
shared resource. Constraints could ensure a consistent catalog, but how
can the dependency be automatically satisfied without defined() or
ensure_resource()?



Well, my original idea for Constraints called for them to handle this issue by synthesizing a resource in the event that there were constraints declared on a resource that was not itself declared.  They were also to set resource parameter values under certain circumstances.  Those are rather trickier propositions than validating declared resources, though, and I doubt they could be achieved without support from the Puppet core.  Relying on such a facility would be better than using defined() or ensure_resource(), though, because the declared constraints collectively describe the requirements on the resource so that you don't have to guess about them.

As an alternative, we had a discussion in the dev group a couple of months back where I advanced the proposition that the distinction between resource declarations and (old style) resource overrides be removed.  This is similar, but not identical, to the longstanding proposition to have Puppet merge identical resource declarations.  As I understand it, though, a different direction was chosen.


John

Reply all
Reply to author
Forward
0 new messages