You can control how Puppet utilizes and acts upon resources with metaparameters. Metaparameters are common attributes that can be used with any resource, including both built-in and custom resource types. Metaparameters control how Puppet deals with the resource.
You can find all metaparameters documented at “Metaparameter Reference” on the Puppet docs site.
As previously mentioned, every resource in the Puppet manifest must refer to a unique resource. Each resource has one attribute (called namevar) that identifies the unique resource on the node. If the namevar attribute is not set, it defaults to the title as a value. You’ve already seen this in previous examples:
file
{
'/tmp/testfile.txt'
:
ensure
=>
present
,
path
=>
'/tmp/testfile.txt'
,
# this was implicit in earlier example
content
=>
"
holy cow!
"
,
}
The namevar attribute uniquely identifies the resource manifestation (e.g., the file on disk in this example), therefore it differs for each resource. Refer to the “Resource Type Reference” on the Puppet docs site to find the namevar for a given resource.
To simplify references to resources, you can add an alias
or “friendly name” to the resource name. This is an essential technique when the resource’s name or location on disk might change from one node to the other. There are two ways to create an alias.
The first way to provide an alias for a resource is to supply a different value in the title
than in the namevar attribute:
file
{
'
the-testfile
'
:
ensure
=>
present
,
path
=>
'/tmp/testfile.txt'
,
content
=>
"
holy cow!
"
,
}
This implicitly creates an alias that can be used as an alternate name for the resource.
The no operation (noop
) attribute allows a resource to be evaluated, but prevents a change from being applied during convergence. This can be useful for auditing purposes, or to identify what would change during convergence. For example, to determine if a newer version of the puppet-agent
package is available without performing the update, set the attribute to true:
package
{
'puppet-agent'
:
ensure
=
>
latest
,
noop
=
>
true
,
}
When this manifest is processed, if a new package version is available it will report what it would have done:
[
vagrant@client
~
]
$
sudo
puppet
apply
/vagrant/manifests/puppet-agent.pp
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/Package
[
puppet-agent
]
/ensure:
current_value
1.3.6-1.el7,
should
be
0:1.4.0-1.el7
(
noop
)
Notice:
Class
[
Main
]
:
Would
have
triggered
'refresh'
from
1
events
Notice:
Stage
[
main
]
:
Would
have
triggered
'refresh'
from
1
events
Notice:
Applied
catalog
in
0.37
seconds
You can get the same behavior by using the --noop
command-line flag on a manifest that doesn’t have the attribute defined:
[
vagrant@client
~
]
$
puppet
apply
--noop
/vagrant/manifests/tmp-testfile.pp
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/Exec
[
echo
-holy-cow
]
/returns:
current_value
notrun,
should
be
0
(
noop
)
Notice:
Class
[
Main
]
:
Would
have
triggered
'refresh'
from
1
events
Notice:
Stage
[
main
]
:
Would
have
triggered
'refresh'
from
1
events
Notice:
Applied
catalog
in
0.01
seconds
There is no way to override the noop
resource attribute with a command-line flag, as the resource attribute has a higher priority than the global option. However, you can place noop = true
as a configuration option in the Puppet configuration file, and override that with a command-line flag.
The audit
attribute defines a list of attributes that you want to track changes to. Define this attribute with an array of attribute names that you wish to track, or the value all
. Changes to any of these values will log a message during a puppet apply
or puppet inspect
run. This could be useful if you don’t want to manage the content of a file, but do want to know every time the content changes:
file
{
'/etc/hosts'
:
audit
=
>
[
'content'
,
'owner'
]
,
}
file
{
'/etc/passwd'
:
audit
=
>
'all'
,
}
This attribute is generally used on resources that Puppet does not manage the values for. If you define this attribute on a resource Puppet manages, you will receive a log notice that Puppet has changed the resource, followed by the audit noticing that Puppet made a change.
Here’s how the preceding manifest would work on the first run:
[
vagrant@client
~
]
$
puppet
apply
/vagrant/manifests/audit.pp
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/File
[
/etc/hosts
]
/content:
audit
change:
newly-recorded
value
{
md5
}
e2b06541983600068fff455f8c11861a
Notice:
/Stage
[
main
]
/Main/File
[
/etc/hosts
]
/owner:
audit
change:
newly-recorded
value
0
Notice:
/Stage
[
main
]
/Main/File
[
/etc/hosts
]
/group:
audit
change:
newly-recorded
value
0
Notice:
Applied
catalog
in
0.01
seconds
Now let’s modify the file, and rerun the audit:
[
vagrant@client
~
]
$
echo
"# adding junk"
|
sudo
tee
-a
/etc/hosts
# adding junk
[
vagrant@client
~
]
$
puppet
apply
/vagrant/manifests/audit.pp
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/File
[
/etc/hosts
]
/content:
audit
change:
previously
recorded
value
{
md5
}
e2b06541983600068fff455f8c11861a
has
been
changed
to
{
md5
}
28c9f9f5a3d060a500d4b57f9875ba32
Notice:
Applied
catalog
in
0.02
seconds
The loglevel
attribute allows you to identify the level at which changes to the resource should be logged. The log levels are similar to syslog log levels, and map to those on Unix and Linux systems:
debug
info
(also called verbose
)notice
warning
err
alert
emerg
crit
For example, log at warning
level whenever the puppet-agent
package is upgraded:
package
{
'puppet-agent'
:
ensure
=
>
latest
,
loglevel
=
>
warning
,
}
Tags can be used for selective enforcement of resources—that is, applying only part of a catalog, such as adding packages, without applying other parts of the catalog, such as restarting or stopping services. Let’s look at an example of this.
Tags can be added to resources as a single string, or as an array of strings. The following manifest will tag both the package and the service with the puppet
tag, and put an additional package
tag on the package resource:
package
{
'puppet-agent'
:
ensure
=>
present
,
tag
=>
[
'package'
,
'puppet'
]
,
}
service
{
'puppet'
:
ensure
=>
running
,
enable
=>
true
,
tag
=>
'puppet'
,
}
If you run this manifest it will start the Puppet agent, which perhaps isn’t desirable right now. So you can apply the manifest and limit action to resources marked with the package
tag:
[
vagrant@client
~
]
$
cd
/vagrant/manifests
[
vagrant@client
~
]
$
sudo
puppet
apply
packagetag.pp
--tags
package
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
Finished
catalog
run
in
0.26
seconds
[
vagrant@client
~
]
$
puppet
resource
service
puppet
service
{
'puppet'
:
ensure
=
>
'stopped'
,
enable
=
>
'false'
,
}
As you can see, the catalog was applied, but the Puppet service was not started. This demonstrates the power of tags in limiting resource evaluation on demand.
package
to the package resource. Puppet automatically adds a tag of the resource type to every resource. We could have applied this manifest with --tags service
to affect only the service, even though the service
tag isn’t shown in the preceding declaration.The --tags
command-line option can accept multiple comma-separated tags. So you could apply the same manifest with --tags package,service
to process both of them.
As of Puppet 4.4, tags can be used to selectively skip over tagged resources—that is, applying only the parts of the catalog that don’t match a tag, such as restarting or stopping services. Let’s look at an example of this:
[
vagrant
@client
~
]
$
sudo
puppet
apply
packagetag
.
pp
-
-
skip_tags
service
Notice
:
Compiled
catalog
for
client
.
example
.
com
in
environment
production
Notice
:
Finished
catalog
run
in
0
.
23
seconds
[
vagrant
@client
~
]
$
puppet
resource
service
puppet
service
{
'puppet'
:
ensure
=
>
'stopped'
,
enable
=
>
'false'
,
}
As you can see, the catalog was applied, but the Puppet service was not started. This had the same effect as our previous run, but can be more useful when trying to isolate a smaller set of resources that should be excluded.
--skip_tags
configuration option will be applied before --tags
, which makes it possible to exclude a set of resources from a larger set of included resources.The schedule
metaparameter can be used to limit when Puppet will make changes to a resource. You can define how many times (repeat
) within a given hour, day, or week (period
) a resource is applied on the node:
schedule
{
'twice-daily'
:
period
=>
daily
,
repeat
=>
2
,
# apply twice within the period
}
The repeat
attribute limits how many times it will be applied within the period. The default is 1
. The period can be any of the following values:
hourly
daily
weekly
monthly
never
The range
attribute limits application to specific hours and minutes in a 24-hour period.
schedule
{
'after-working-hours'
:
period
=>
daily
,
range
=>
'17:00 - 08:00'
,
# between 5 p.m. and 8 a.m.
}
The weekday
attributes limit application to specific days of the week.
schedule
{
'business-hours'
:
period
=>
hourly
,
repeat
=>
1
,
# apply once per hour
range
=>
'08:00 - 17:00'
,
# between 8 a.m. and 5 p.m.
weekday
=>
[
'Mon'
,
'Tue'
,
'Wed'
,
'Thu'
,
'Fri'
]
,
# on weekdays
}
weekday
should be an array whose items are either a number, the three-letter name, or the full English name for a weekday. The following example is valid, albeit confusing to read:
schedule
{
'odd-days'
:
weekday
=>
[
'Mon'
,
'3'
,
'Friday'
]
,
}
If the range
crosses the midnight boundary and the weekday
attribute is defined, then the weekday applies to the start of the time period, not when it ends. For example, a resource with the following schedule could be applied any time between Sunday night and Monday morning:
schedule
{
'sunday-night'
:
range
=>
'20:00 - 06:00'
,
weekday
=>
[
'Sunday'
]
,
}
Add the schedule
metaparameter to a resource to limit when the resource is applied. For example, if we want to limit upgrades of Puppet until after the normal working day has ended, we might declare it this way:
package
{
'puppet-agent'
:
ensure
=
>
latest
,
schedule
=
>
'after-working-hours'
,
}
The value of the schedule
metaparameter must be the name of a schedule
resource you’ve declared.
You can find the complete documentation for the schedule
resource at “Puppet Types: Schedule” on the Puppet docs site.
The schedule
resource has an additional (and somewhat confusing) attribute named periodmatch
. The current documentation in the Puppet type reference is vague about the meaning of this parameter, so I’m going to spell this one out. periodmatch
takes only two values:
distance
(default)period
distance (an hour, a day, a week) has passed. If the repeat
attribute is specified, the distance is calculated as period
/repeat
(e.g., four times in a day)number
periodmatch
is set to number
, the repeat
attribute cannot be greater than 1
.The effect of this parameter is not intuitive, and you may find yourself coming back to reread this section. Let’s provide some concrete examples. Imagine that you ran puppet apply
on a manifest with a file resource at 01:57. Then you deleted the file it created. Say you had a schedule like the following:
schedule
{
'once-every-hour'
:
period
=>
hourly
,
periodmatch
=>
distance
,
}
file
{
'/tmp/test.txt'
:
ensure
=>
file
,
schedule
=>
'once-every-hour'
,
}
If you ran Puppet every minute with a schedule like this, it would be 02:57, or 60 minutes before the file was re-created.
A periodmatch
of number
means that the resource is evaluated once within the same number—for example, the second hour. Say you used a schedule like the following and ran it once at 1:57, before deleting the file:
schedule
{
'once-in-an-hour'
:
period
=>
hourly
,
periodmatch
=>
number
,
}
file
{
'/tmp/test.txt'
:
ensure
=>
file
,
schedule
=>
'once-in-an-hour'
,
}
In this case, the file would be re-created in the first minute of the second hour, only three minutes later!
$
while
true
;
do
date
;
rm
-f
/tmp/test.txt
;
puppet
apply
/vagrant/manifests/schedule.pp
;
sleep
60
;
done
Sun
Sep
20
03:57:10
UTC
2015
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/File
[
/tmp/test.txt
]
/ensure:
created
Notice:
Applied
catalog
in
0.01
seconds
Sun
Sep
20
03:58:12
UTC
2015
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
Applied
catalog
in
0.02
seconds
Sun
Sep
20
03:59:13
UTC
2015
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
Applied
catalog
in
0.02
seconds
Sun
Sep
20
04:00:15
UTC
2015
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/File
[
/tmp/test.txt
]
/ensure:
created
Notice:
Applied
catalog
in
0.01
seconds
When you use the default distance
value with a repeat
greater than 1
, the period is divided evenly by the value of repeat
. With a period
of daily
and a repeat
of 4
, the resource will be evaluated no sooner than six hours after the last application.
schedule
only limits when the resource will be evaluated. It does not schedule Puppet to apply the catalog. On the first catalog application after the period expires, Puppet will evaluate the resource again.If Puppet applies the catalog every 30 minutes (default config), then an hourly
schedule will limit the resource evaluation to every other standard run. Using an hourly
period with a repeat of 2
will only prevent ad hoc runs in between the normal runs from affecting the resource.
The manifest /vagrant/manifests/schedule.pp defines three hourly schedules and three files using those schedules. To see this in action, apply this manifest in a loop as follows and examine the results:
$
while
true
;
do
date
;
puppet
apply
/vagrant/manifests/schedule.pp
;
sleep
60
;
done
There is a “feature” of Puppet that may surprise you. A resource that is not evaluated because it falls outside the configured schedule
will succeed for the purposes of dependency evaluation. This means that if the resource creates something that a later resource utilizes, like a configuration file, the dependent resource will fail.
Here’s an example:
schedule
{
'workhours'
:
range
=>
'08:00 - 17:00'
,
}
file
{
'/tmp/workhours.txt'
:
ensure
=>
file
,
content
=>
'Open for business'
,
schedule
=>
'workhours'
,
}
exec
{
'use file'
:
path
=>
'/bin:/usr/bin'
,
command
=>
'cat /tmp/workhours.txt'
,
require
=>
File
[
'/tmp/workhours.txt'
]
,
}
If we apply this manifest outside of work hours, the file is not created because it falls outside the schedule. The following exec
resource then fails because a file it needs doesn’t exist:
[
vagrant@client
~
]
$
puppet
apply
/vagrant/manifests/unscheduled.pp
Notice:
Compiled
catalog
for
client.example.com
in
environment
production
Notice:
/Stage
[
main
]
/Main/Exec
[
use
file
]
/returns:
cat:
/tmp/workhours.txt:
No
such
file
or
directory
Error:
cat
/tmp/workhours.txt
returned
1
instead
of
one
of
[
0
]
Error:
/Stage
[
main
]
/Main/Exec
[
use
file
]
/returns:
change
from
notrun
to
0
failed:
cat
/tmp/workhours.txt
returned
1
instead
of
one
of
[
0
]
Notice:
Applied
catalog
in
0.02
seconds
There are a few ways to avoid this problem.
onlyif
to check if the file exists first (only works with exec
resources).--ignoreschedules
to ensure that all resources are created.The final suggestion is perhaps the single best option. The first time you run Puppet to initialize a new node, you may want to enable ignoreschedules
to ensure that every resource is created. The schedule will prevent further changes to those resources until the specified range of time.
You can declare defaults for all resources of a given type. If a resource declaration of the same type does not explicitly declare the attribute, then the attribute value from the resource default will be used.
Resource defaults are declared with a capitalized resource type and no title. For example, the following resource definition would limit package
evaluation to after working hours:
Package
{
schedule
=
>
'after-working-hours'
,
}
Defaults can be defined multiple times, causing confusion for the people who have to debug the code. A default specified later in the manifest affects resources above it. Avoid this whenever possible.
Resource defaults also bleed into other code that is called or declared within the manifest scope. This can have surprising consequences. A more readable and maintainable method is to place the default attribute values into a hash, and add it to resources with the splat operator, as shown in “Defining Attributes with a Hash”.
The problems with resource defaults and variable scope are explained in “Understanding Variable Scope”.
This chapter introduced you to attributes that control how resources are processed:
alias
provides friendly names for resources with complicated or variable titles.noop
prevents changes to the resource.audit
logs changes to a resource outside of Puppet.loglevel
controls log output on a per-resource basis.tags
identifies resources to be evaluated on a filtered Puppet run.schedule
limits when or how often changes to a resource are permitted.Using these attributes provides fine-grained control over how and when your resources are evaluated.