Language: Defined Resource Types
Defined resource types (also called defined types or defines) are blocks of Puppet code that can be evaluated multiple times with different parameters. Once defined, they act like a new resource type: you can cause the block to be evaluated by declaring a resource of that new type.
Defines can be used as simple macros or as a lightweight way to develop fairly sophisticated resource types.
Syntax
Defining a Type
# /etc/puppetlabs/puppet/modules/apache/manifests/vhost.pp
define apache::vhost ($port, $docroot, $servername = $title, $vhost_name = '*') {
include apache # contains Package['httpd'] and Service['httpd']
include apache::params # contains common config settings
$vhost_dir = $apache::params::vhost_dir
file { "${vhost_dir}/${servername}.conf":
content => template('apache/vhost-default.conf.erb'),
# This template can access all of the parameters and variables from above.
owner => 'www',
group => 'www',
mode => '644',
require => Package['httpd'],
notify => Service['httpd'],
}
}
This creates a new type called apache::vhost
.
The general form of a type definition is:
- The
define
keyword - The name of the defined type
- An optional set of parameters, which consists of:
- An opening parenthesis
- A comma-separated list of parameters, each of which consists of:
- A new variable name, including the
$
prefix - An optional equals sign and default value (any data type)
- A new variable name, including the
- An optional trailing comma after the last parameter
- A closing parenthesis
- An opening curly brace
- A block of arbitrary Puppet code, which generally contains at least one resource declaration
- A closing curly brace
The definition does not cause the code in the block to be added to the catalog; it only makes it available. To execute the code, you must declare one or more resources of the defined type.
Declaring an Instance
Instances of a defined type (often just called “resources”) can be declared the same way a normal resource is declared. (That is, with a type, title, and set of attribute/value pairs.)
The parameters used when defining the type become the attributes (without the $
prefix) used when declaring resources of that type. Parameters which have a default value are optional; if they are left out of the declaration, the default will be used. Parameters without defaults must be specified.
To declare a resource of the apache::vhost
type from the example above:
apache::vhost {'homepages':
port => 8081,
docroot => '/var/www-testhost',
}
Behavior
If a defined type is present, you can declare resources of that type anywhere in your manifests. See “Location” below for details.
Declaring a resource of the type will cause Puppet to re-evaluate the block of code in the definition, using different values for the parameters.
Parameters and Attributes
Every parameter of a defined type can be used as a local variable inside the definition. These variables are not set with normal assignment statements; instead, each instance of the defined type uses its attributes to set them:
apache::vhost {'homepages':
port => 8081, # Becomes the value of $port
docroot => '/var/www-testhost', # Becomes the value of $docroot
}
$title
and $name
Every defined type gets two “free” parameters, which are always available and do not have to be explicitly added to the definition:
$title
is always set to the title of the instance. Since it is guaranteed to be unique for each instance, it is useful when making sure that contained resources are unique. (See “Resource Uniqueness” below.)$name
defaults to the value of$title
, but users can optionally specify a different value when they declare an instance. This is only useful for mimicking the behavior of a resource with a namevar, which is usually unnecessary. If you are wondering whether to use$name
or$title
, use$title
.
Unlike the other parameters, the values of $title
and $name
are already available inside the parameter list. This means you can use $title
as the default value (or part of the default value) for another attribute:
define apache::vhost ($port, $docroot, $servername = $title, $vhost_name = '*') { ...
Resource Uniqueness
Since multiple instances of a defined type might be declared in your manifests, you must make sure that every resource in the definition will be different in every instance. Failing to do this will result in compilation failures with a “duplicate resource declaration” error.
You can make resources different across instances by making their titles and names/namevars include the value of $title
or another parameter.
file { "${vhost_dir}/${servername}.conf":
Since $title
(and possibly other parameters) will be unique per instance, this ensures the resources will be unique as well.
Containment
Every instance of a defined type contains all of its unique resources. This means any relationships formed between the instance and another resource will be extended to every resource that makes up the instance.
Metaparameters
The declaration of a defined type instance can include any metaparameter. If it does:
- Every resource contained in the instance will also have that metaparameter. So if you declare a defined resource with
noop => true
, every resource contained in it will also havenoop => true
, unless they specifically override it. Metaparameters which can take more than one value (like the relationship metaparameters) will merge the values from the container and any specific values from the individual resource. - The value of the metaparameter can be used as a variable in the definition, as though it were a normal parameter. (For example, in an instance declared with
require => Class['ntp']
, the local value of$require
would beClass['ntp']
.)
Resource Defaults
Just like with a normal resource type, you can declare resource defaults for a defined type:
# /etc/puppetlabs/puppet/manifests/site.pp
Apache::Vhost {
port => 80,
}
In this example, every resource of the type would default to port 80 unless specifically overridden.
Location
Defined types can (and should) be stored in modules. Puppet is automatically aware of any defined types in a valid module and can autoload them by name. Definitions should be stored in the manifests/
directory of a module with one definition per file and each filename should reflect the name of its type. See Module Fundamentals for more details.
Aside: Best Practices
You should usually only load defined types from modules. Although the additional options below this aside will work, they are not recommended.
You can also put type definitions in the site manifest. If you do so, they may be placed anywhere in the file and are not parse-order dependent.
Type definitions may also be placed inside class definitions; however, this limits their availability to that class and is not recommended for any purpose. This is not formally deprecated in Puppet 3, but may become so in a future release.
Naming
The characters allowed in a defined type’s name are listed here.
If the definition is stored in a module, its name must reflect its place in the module with its namespace. See Module Fundamentals for details.
Note that if a type’s name has one or more namespaces in it, each name segment must be capitalized when writing a resource reference, collector, or resource default. (For example, a reference to the vhost resource declared above would be Apache::Vhost['homepages']
.)