Scope
A scope is a specific area of code that is partially isolated from other areas of code.
Resource titles, which are all global.
Resource references, which can refer to a resource declared in any scope.
A particular scope has access to its own contents, and also receives additional contents from its parent scope, node scope, and top scope. The rules for how Puppet determines a local scope’s parent are described in scope lookup rules.
Top scope can access variables and defaults only from its own scope.
Node scope can access variables and defaults from its own scope and top scope.
Each of the
example::parent
,example::other
, andexample::four
classes can access variables and defaults from their own scope, node scope, and top scope.The
example::child
class can access variables and defaults from its own scope, theexample::parent
scope, node scope, and top scope.
Top scope
Code that is outside any class definition, type definition, or node definition exists at top scope. Variables and defaults declared at top scope are available everywhere.
# site.pp
$variable = "Hi!"
class example {
notify {"Message from elsewhere: $variable":}
}
include example
$ puppet apply site.pp
notice: Message from elsewhere: Hi!
Node scope
Code inside a node definition exists at node scope. Only one node scope can exist at a time because only one node definition can match a given node.
Variables and defaults declared at node scope are available everywhere except top scope.
# site.pp
$top_variable = "Available!"
node 'puppet.example.com' {
$variable = "Hi!"
notify {"Message from here: $variable":}
notify {"Top scope: $top_variable":}
}
notify {"Message from top scope: $variable":}
$ puppet apply site.pp
notice: Message from here: Hi!
notice: Top scope: Available!
notice: Message from top scope:
Local scopes
Code inside a class definition, defined type, or lambda exists in a local scope.
Variables and defaults declared in a local scope are only available in that scope and its children. There are two different sets of rules for when scopes are considered related. For more information, see scope lookup rules.
# /etc/puppetlabs/code/modules/scope_example/manifests/init.pp
class scope_example {
$variable = "Hi!"
notify {"Message from here: $variable":}
notify {"Node scope: $node_variable Top scope: $top_variable":}
}
# /etc/puppetlabs/code/environments/production/manifests/site.pp
$top_variable = "Available!"
node 'puppet.example.com' {
$node_variable = "Available!"
include scope_example
notify {"Message from node scope: $variable":}
}
notify {"Message from top scope: $variable":}
$ puppet apply site.pp
notice: Message from here: Hi!
notice: Node scope: Available! Top scope: Available!
notice: Message from node scope:
notice: Message from top scope:
Overriding received values
Variables and defaults declared at node scope can override those received from top scope. Those declared at local scope can override those received from node and top scope, as well as any parent scopes. If multiple variables with the same name are available, Puppet uses the most local one.
# /etc/puppetlabs/code/modules/scope_example/manifests/init.pp
class scope_example {
$variable = "Hi, I'm local!"
notify {"Message from here: $variable":}
}
# /etc/puppetlabs/code/environments/production/manifests/site.pp
$variable = "Hi, I'm top!"
node 'puppet.example.com' {
$variable = "Hi, I'm node!"
include scope_example
}
$ puppet apply site.pp
notice: Message from here: Hi, I'm local!
Resource defaults are processed by attribute rather than as a block. Thus, defaults that declare different attributes are merged, and only the attributes that conflict are overridden.
/tmp/example
would be a
directory owned by the puppet
user, and would
combine the defaults from top and local
scope:# /etc/puppetlabs/code/modules/scope_example/manifests/init.pp
class scope_example {
File { ensure => directory, }
file {'/tmp/example':}
}
# /etc/puppetlabs/code/environments/production/manifests/site.pp
File {
ensure => file,
owner => 'puppet',
}
include scope_example
Scope of external node classifier data
Variables provided by an ENC are set at the top scope. However, all of the classes assigned by an ENC are declared at the node scope.
Named scopes and anonymous scopes
A class definition creates a named scope, whose name is the same as the class’s name. Top scope is also a named scope; its name is the empty string.
Node scope and the local scopes created by lambdas and defined resources are anonymous and cannot be directly referenced.
Accessing out-of-scope variables
Variables declared in named scopes can be referenced directly from anywhere, including scopes that otherwise would not have access to them, by using their qualified global name.
$<NAME OF SCOPE>::<NAME OF VARIABLE>
$local_copy
is set
to the value of the $confdir
variable from the apache::params
class:include apache::params
$local_copy = $apache::params::confdir
A class must be declared to access its variables; just having the class available in your modules is insufficient.
This means the availability of out-of-scope variables is evaluation-order dependent.
Make sure you only access out-of-scope variables if the class accessing them can
guarantee that the other class is already declared, usually by explicitly declaring it
with include
before trying to read its variables.
Because the top scope’s name is the empty string, $::my_variable
refers to the top-scope value of $my_variable
, even if $my_variable
has a
different value in local scope.
Variables declared in anonymous scopes can only be accessed normally and do not have qualified global names.
Scope lookup rules
The scope lookup rules determine when a local scope becomes the parent of another local scope.
Static scope for variables.
Dynamic scope for resource defaults.
Static scope
-
Classes can receive parent scopes by class inheritance, using the
inherits
keyword. A derived class receives the contents of its base class in addition to the contents of node and top scope. -
A lambda’s parent scope is the local scope in which the lambda is written. It can access variables in that scope by their short names.
All other local scopes have no parents — they receive their own contents, the contents of node scope (if applicable), and top scope.
-
Scope contents are predictable and do not depend on evaluation order.
-
Scope contents can be determined simply by looking at the relevant class definition; the place where a class or defined type is declared has no effect. The only exception is node definitions — if a class is declared outside a node, it does not receive the contents of node scope.
Dynamic scope
-
Each scope has only one parent, but can have an unlimited chain of grandparents, and receives the merged contents of all of them, with nearer ancestors overriding more distant ones.
-
The parent of a derived class is its base class.
-
The parent of any other class or defined resource is the first scope in which it was declared.
-
When you declare a derived class whose base class hasn’t already been declared, the base class is immediately declared in the current scope, and its parent assigned accordingly. This effectively “inserts” the base class between the derived class and the current scope. If the base class has already been declared elsewhere, its existing parent scope is not changed.
-
A scope’s parent cannot be identified by looking at the definition of a class — you must examine every place where the class or resource might have been declared.
-
In some cases, you can only determine a scope’s contents by executing the code.
-
Because classes can be declared multiple times with the
include
function, the contents of a given scope are evaluation-order dependent.