4
votes

Just getting started with Puppet, and I'm having trouble with my first template. It should be very easy, but I can't figure it out.

I have a module "base" at

/etc/puppet/modules/base/
    ./manifests
    ./manifests/service.pp
    ./manifests/init.pp
    ./manifests/params.pp
    ./manifests/config.pp
    ./manifests/install.pp
    ./templates
    ./templates/puppet.conf.erb

There's other stuff, but it's not necessary.

base/manifests/init.pp:

class base {
  include base::install, base::service, base::config, base::params
}

base/manifests/config.pp

class base::config {
  include base::params

  File {
    require => Class["base::install"],
    ensure => present,
    owner => root,
    group => root,
  }

  file { "/etc/puppet/puppet.conf":
    mode => 0644,
    content => template("base/puppet.conf.erb"),
    require => Class["base::install"],
    nofity => Service["puppet"],
  }
...

base/manifests/params.pp

class base::params {
  $puppetserver = "pup01.sdirect.lab"
}

Finally the interesting part of the template at base/templates/puppet.conf.erb

...
server=<% puppetserver %>

The error message:

err: Failed to parse template base/puppet.conf.erb: Could not find value for 'puppetserver' at /etc/puppet/modules/base/manifests/config.pp:13 on node ...

I don't get what the problem is. I've copied this part straight out of the Pro Puppet book.

Could someone show me where $puppetserver should be defined and how?

3

3 Answers

16
votes

The issue is that the name "puppetserver" needs to be fully qualified so Puppet can find the value, since it's defined in a different scope to the one the template is evaluated in.

The variable is defined in base::params so can only be referred to simply as "puppetserver" in that scope. When you're evaluating the template from within base::config, you're in a different scope and so you can't refer to the variable simply by its short name. The "include" adds the other class to the catalog, but doesn't change these rules.

This means to access it, you fully qualify it with the class name: base::params::puppetserver. If you were using it in the manifest itself, this would be $base::params::puppetserver. You'll see similar examples in Pro Puppet in the ssh::config and ssh::service classes where it refers to "ssh_service_name" in the params class (pages 43-45).

To access the variable in a template it's a bit different, use scope.lookupvar("base::params::puppetserver"). Taking your full example and adding a missing equals sign (to output the value) in the template:

...
server=<%= scope.lookupvar("base::params::puppetserver") %>

There's a bit more information about scoping on the Scope and Puppet as of 2.7 page.

(Edit: looks like it's listed on the confirmed errata page too with the same solution.)

6
votes

Answer #1 is technically correct, but results in very verbose templates.

You can shorten them by bringing variable values from other classes into your own class scope:

class base::config {
  include base::params
  $puppetserver = $base::params::puppetserver
  ...
}

And then use them in your template as expected:

server=<% puppetserver %>
1
votes

You could also use inherits:

class puppet::config inherits puppet::params {
....

In this way you don't have to define $puppetserver again in this class.