Multiple resource bodies

If a resource expression includes more than one resource body, the expression will declare multiple resources of that resource type. (A resource body is a title and a set of attributes; each body must be separated from the next one with a semicolon.)

Each resource in an expression is almost completely independent of the others, and they can have completely different values for their attributes. The only connections between resources that share an expression are:

They all have the same resource type.

They can all draw from the same pool of default values, if a resource body with the special title default is present. (See below for details.)

Value of a resource expression

Resource declarations are expressions in the Puppet language — they always have a side effect (adding a resource to the catalog), but they also resolve to a value.

The value of a resource declaration is an array of resource references, with one reference for each resource the expression describes.

Note: A resource declaration has extremely low precedence; in fact, it’s even lower than the variable assignment operator (=). This means that in almost every place where you can use a resource declaration for its value, you will need to surround it with parentheses to properly associate it with the expression that uses the value.

Per-expression default attributes

If a resource expression includes a resource body whose title is the special value default, Puppet won’t create a new resource named “default.”

Instead, every other resource in that expression will use attribute values from the default body if it doesn’t have an explicit value for one of those attributes.

This is useful because it lets you set many attributes at once (like with an array of titles), but also lets you override some of them.

You cannot set any attribute more than once for a given resource; if you try, Puppet will raise a compilation error. This means:

If you use a hash to set attributes for a resource, you cannot set a different, explicit value for any of those attributes. (If mode is present in the hash, you can’t also set mode => "0644" in that resource body.)

You can’t use the * attribute multiple times in one resource body, since * itself acts like an attribute.

If you want to use some attributes from a hash and override others, you can either use a hash to set per-expression defaults, or use the + (merging) operator to combine attributes from two hashes (with the right-hand hash overriding the left-hand one).

Using an abstract resource type

Since a resource expression can accept a resource type data type as its resource type, you can use a Resource[<TYPE>] value to specify a non-literal resource type, where the <TYPE> portion can be read from a variable.

This lets you declare resources without knowing in advance what type of resources they’ll be, which can enable interesting transformations of data into resources. For a demonstration, see the create_resources example below.

Arrays of titles

If you specify an array of strings as the title of a resource body, Puppet will create multiple resources with the same set of attributes. This is useful when you have many resources that are nearly identical.

Note that if you do this, you must let the namevar attributes of these resources default to their titles. You can’t specify an explicit value for the namevar, because it will apply to all of those resources.

Adding or modifying attributes

Although you cannot declare the same resource twice, you can add attributes to an already-declared resource. In certain circumstances, you can also override attributes.

Normally, you can only use this syntax to add previously unmanaged attributes to a resource; it cannot override already-specified attributes. However, within an inherited class, you can use this idiom to override attributes.

It can always override already-specified attributes, regardless of class inheritance.

It can affect large numbers of resources at once.

It will implicitly realize any virtual resources that the collector matches. If you are using virtual resources at all, you must use extreme care when constructing collectors that are not intended to realize resources, and would be better off avoiding non-realizing collectors entirely.

Since it ignores class inheritance, you can override the same attribute twice, which results in a evaluation-order dependent race where the final override wins.

Advanced examples

Local resource defaults

Since classic resource default statements are subject to dynamic scope, they can escape the place where they’re declared and affect unpredictable areas of code. Sometimes this is powerful and useful, and other times it’s really bad, like when you want to set defaults for your module’s file resources, but you’re also declaring classes and defined resources from other modules and want to avoid any contagious effect.

Implementing the create_resources function

Since the Puppet 2.7 era, the create_resources function has been a useful tool of last resort when creating modules that were too complex to express in the Puppet language. It lets you use anything you want to create a data structure describing any number of resources, then add all of those resources to the catalog.