6

I would like to reference variables inside instances of defined types. For example, what can I do to reference $x and $y of foo a in bar b?

 define foo($x, $y) {
  }

  define bar($foo) {
          notify { "${::$foo::x}": } # <- how to make this reference work?
  }

  foo { 'a':
          x => 'oh bar may you reference me',
          y => 'please'
  }

  bar { 'b':
          foo     => Foo['a'],
          require => Foo['a']
  }

The reason why I would like this to work is that a foo instance may contain many values that I wouldn't like to repeat to each and every resource that might need them. Instead of passing those values again and again, thus repeating myself, I'd rather pass a reference to their container.

I've been looking all over and tried a bunch of things, but can't seem to find an answer to this question anywhere. I know it is possible to amend attributes, reference resources and read class attributes, but is it possible to read attributes of a resource/defined type? If it isn't what is then the best possible work around?

Lodewijk Bogaards
  • 19,777
  • 3
  • 28
  • 52

2 Answers2

10

I've actually just found out that Puppetlab's stdlib module includes a getparam function that can be used to solve this problem.

So here is finally the solution to my own question:

define foo($x, $y) {
}

define bar($foo) {
  notify { getparam(Foo[$foo], 'x'): }
  notify { getparam(Foo[$foo], 'y'): }
}

foo { 'a':
  x => 'oh bar may you reference me',
  y => 'please'
}

bar { 'b':
  foo  => 'a'
}

Please note that the require => Foo['a'] in the definition of Bar['b'] does not appear to be needed.

Lodewijk Bogaards
  • 19,777
  • 3
  • 28
  • 52
2

It doesn't seem that you can access a defined type's attributes. Possible explanation here. What you can do however, is externalize it via hiera.

Hiera is a great way to separate your manifest logic from the data populating it, but it is not difficult to set up.

Installing

In my first try I was trying to access hiera variables by class reference; foo::a for example, but that doesn't work for defined types.

Using http://drewblessing.com/blog/-/blogs/puppet-hiera-implement-defined-resource-types-in-hiera as a guide, you can put declare all those attributes in hiera with a simple config:

Configuring:

hiera.yaml

:backends:
  - yaml
:yaml:
  :datadir: $hiera_dir
:hierarchy:
  - common

$hiera_dir/common.yaml

foo:
  a:
    x: 'oh bar may you reference me'
    y: 'please'

And then in your puppet manifest:

define foo ($x, $y) {
}

define bar($foo) {
    require create_my_foos

    $all_foos = hiera('foo')

    # This is just for proof of concept, to show that the variable can be passed.
    file { '/tmp/output.txt':
        content => $all_foos[$foo]['x']
    }
}

class create_my_foos {  
    $foo_instances = hiera('foo', [])
    create_resources('foo', $foo_instances)
}

bar { 'b':
    foo => 'a'
}

Now you can access foo's variables by calling the hiera('foo') function to get an array of foo's attributes, and do array lookups to get the exact parameter you need.

Note that hiera only looks up top-level keys, so you can't do hiera('foo'['a']['x]).

xiankai
  • 2,773
  • 3
  • 25
  • 31
  • 1
    Certainly not the answer I was hoping for, but thanks! I've tried your workaround and it does work. I will accept your answer with bounty unless somebody else can come up with a way of accessing foo.x without the requirement that foo.x is accessible through hiera within the next couple of days. – Lodewijk Bogaards Oct 02 '13 at 15:59
  • I am also curious as to why this is not possible using the Puppet language alone. – Lodewijk Bogaards Oct 02 '13 at 16:14
  • I am also quite interested in why, so I did a bit more digging around and found something of interest - http://docs.puppetlabs.com/guides/scope_and_puppet.html I have updated my answer to include it. – xiankai Oct 03 '13 at 05:20
  • I actually read this before, but this article doesn't seem to explain why. I am guessing it has something to do with that Puppet runs all its functions and interpret all its variables during what I would call compile-time. – Lodewijk Bogaards Oct 06 '13 at 11:49
  • I found a way! See my answer. – Lodewijk Bogaards Mar 15 '14 at 13:28