outcome of this is that you cannot redefine a variable inside the same scope it was defined in, like our node. Let’s take another example, of a class this time instead of a node:
class ssh_sudo {
$package = "openssh"
package { $package: ensure => installed }
$package = "sudo"
package { $package: ensure => installed }
}
You can see that we’ve tried to define the
$package
variable twice. If we were to try to compile and apply this configuration, the Puppet agent would return the following error:
err: Cannot reassign variable package at /etc/puppet/modules/ssh/manifests/init.pp:5
Note The error helpfully also tells us the file, and line number in the file, where we’ve tried to redefine the variable.
So what’s a scope? Each class, definition, or node introduces a new scope, and there is also a top scope for everything defined outside of those structures. Scopes are created hierarchically and the important thing you need to remember about scope hierarchy is that it is created when Puppet code is evaluated, rather than when it is defined, for example:
$package = "openssh"
class ssh {
package { $package:
ensure => installed,
}
}
class ssh_server
include ssh
$package = "openssh-server"
}
include ssh_server
Here a top level scope, in which
$package
is defined, is present. Then there’s a scope for the
ssh_server
class and a scope below that for the
ssh
class. When Puppet runs the
$package
variable will have a value of
"openssh-server"
because this is what the variable was when evaluation occurred.
Naturally, in these different scopes, you can reassign the value of a variable:
class apache {
$apache = 1
}
class passenger {
$apache = 2
}
The same variable can be used and defined in both the
apache
and
passenger
classes without generating an error because they represent different scopes.
Going back to node inheritance, you can probably see how this dynamic scoping is going to be potentially confusing, for example:
class apache {
$apacheversion = "2.0.33"
package { "apache2":
ensure => $apacheversion,
}
}
node 'web.example.com' {
include apache
}
node 'web2.example.com' inherits 'web.example.com' {
$apacheversion = "2.0.42"
}
Here we’ve created a class called
apache
and a package resource for the
apache2
package. We’ve also created a variable called
$apacheversion
and used that as the value of the
ensure
attribute of the package resource. This tells Puppet that we want to install version 2.0.33 of Apache. We’ve then included our
apache
class in a node,
web.example.com
.
But we’ve also decided to create another node,
web2.example.com
, which inherits the contents of the
web.example.com
node. In this case, however, we’ve decided to install a different Apache version and therefore we specified a new value for the
$apacheversion
variable. But instead of using this new value, Puppet will continue to install the 2.0.33 version of Apache because the
$apacheversion
variable is maintained in its original scope of the
web.example.com
node and the new variable value is ignored.
There is a work-around for this issue that you can see here:
class apache {
$apacheversion = "2.0.33"
package { "apache2":
ensure => $apacheversion,
}
}
class base {
include apache
}
node 'web.example.com' {
$apacheversion = "2.0.42"
include base
}
Instead of defining a
base
node we’ve defined a
base
class that includes the
apache
class. When we created our node, we specified the
$apacheversion
we want and then included the
base
class, ensuring we’re in the right scope. We could put other like items in our
base
class and specify any required variables.
Note You can learn more about variable scoping, workarounds and related issues at
http://projects.puppetlabs.com/projects/puppet/wiki/Frequently_Asked_Questions#Common+Misconceptions
.
With Puppet installed and node
Susan McBride
Cathryn Cade
Sara Gran
Benjamin Lebert
A.J. Downey
Masha Leyfer
Amy Durham
Lawrence Block
Elsebeth Egholm
David J. Guyton