Relationships and ordering

Resources are included and applied in the order they are defined in their manifest, but only if the resource has no implicit relationship with another resource, as this can affect the declared order. To manage a group of resources in a specific order, explicitly declare such relationships with relationship metaparameters, chaining arrows, and the require function.

To override Puppet's default manifest ordering, declare an explicit relationship between resources. All relationships cause Puppet to manage specific resources before other resources. Relationships are not limited by evaluation-order; you can declare a relationship with a resource before that resource has been declared.

Refreshing and notification

Some resource types can refresh when one of their dependencies changes. For example, some services must restart when their configuration files change, so service resources can refresh by restarting the service.

The built-in resource types that can refresh are service, exec, and package. For specific details about these types, see the resource reference.

To specify that a resource must refresh when a related resource changes, create a notifying relationship with the subscribe or notify metaparameters or the notification chaining arrow (~>). When a resources changes, it sends a refresh event to any resources that subscribe to it. Those resources that are subscribed receive the refresh event.

When receiving refresh events:
  • If a resource gets a refresh event during a run, and its resource type has a refresh action, it performs that action.

  • If a resource gets a refresh event, but its resource type cannot refresh, nothing happens.

  • If a class or defined resource gets a refresh event, every resource it contains also gets a refresh event.

  • A resource can perform its refresh action up to once per run. If it receives multiple refresh events, they're combined, and the resource refreshes only once.

When sending refresh events:
  • If a resource is not in its desired state, and Puppet makes changes to it during a run, it sends a refresh event to any subscribed resources.

  • If a resource performs its refresh action during a run, it sends a refresh event to any subscribed resources.

  • If Puppet changes or refreshes any resource in a class or defined resource, that class or defined resource sends a refresh event to any subscribed resources.

If non-operational (no-op) mode is enabled:
  • The resource does not refresh when it receives a refresh event. Instead, Puppet logs a message stating what would have happened.

  • The resource does not send refresh events to subscribed resources. Instead, Puppet logs messages stating what would have happened to any resources further down the subscription chain.

For more information about refresh behavior, see the types documentation.

Automatic relationships

Certain resource types can have automatic relationships with other resources, using autorequire, autonotify, autobefore, or autosubscribe. This creates an ordering relationship without you explicitly stating one.

Puppet establishes automatic relationships between types and resources when it applies a catalog. It searches the catalog for any resources that match certain rules and processes them in the correct order, sending refresh events if necessary. If any explicit relationship, such as those created by chaining arrows, conflicts with an automatic relationship, the explicit relationship take precedence.

Missing dependencies

If one of the resources in a relationship is never declared, compilation fails with one of the following errors:
  • Could not find dependency <OTHER RESOURCE> for <RESOURCE>
  • Could not find resource '<OTHER RESOURCE>' for relationship on '<RESOURCE>

Failed dependencies

If Puppet fails to apply the prior resource in a relationship, it skips the subsequent resource and log the following messages:
notice: <RESOURCE>: Dependency <OTHER RESOURCE> has failures: true warning: <RESOURCE>: Skipping because of failed dependencies
It then continues to apply any unrelated resources. Any resources that depend on the skipped resource are also skipped. This helps prevent an inconsistent system state, rather than attempting to apply a resource that might have broken prerequisites.

Dependency cycles

If two or more resources require each other in a loop, Puppet compiles the catalog but won’t be able to apply it. Puppet logs an error like the following, and attempts to help identify the cycle:
err: Could not apply complete catalog: Found 1 dependency cycle:
(<RESOURCE> => <OTHER RESOURCE> => <RESOURCE>)
Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz
To locate the directory containing the graph files, run puppet agent --configprint graphdir.

Relationship metaparameters

You can use certain metaparameters to establish relationships by setting any of them as an attribute in any resource.

The following video gives you an overview of metaparameters:

Set the value of any relationship metaparameter to either a resource reference or an array of references that point to one or more target resources:
  • before: Applies a resource before the target resource.

  • require: Applies a resource after the target resource.

  • notify: Applies a resource before the target resource. The target resource refreshes if the notifying resource changes.

  • subscribe: Applies a resource after the target resource. The subscribing resource refreshes if the target resource changes.

If two resources need to happen in order, you can either put a before attribute in the prior one or a require attribute in the subsequent one; either approach creates the same relationship. The same is true of notify and subscribe.

The two examples below create the same ordering relationship, ensuring that the openssh-server package is managed before the sshd_config file:

package { 'openssh-server':
  ensure => present,
  before => File['/etc/ssh/sshd_config'],
}

file { '/etc/ssh/sshd_config':
  ensure  => file,
  mode    => '0600',
  source  => 'puppet:///modules/sshd/sshd_config',
  require => Package['openssh-server'],
}
The two examples below create the same notifying relationship, so that if Puppet changes the sshd_config file, it sends a notification to the sshd service:

file { '/etc/ssh/sshd_config':
  ensure => file,
  mode   => '0600',
  source => 'puppet:///modules/sshd/sshd_config',
  notify => Service['sshd'],
}

service { 'sshd':
  ensure    => running,
  enable    => true,
  subscribe => File['/etc/ssh/sshd_config'],
}
Because an array of resource references can contain resources of differing types, these two examples also create the same ordering relationship. In both examples, Puppet manages the openssh-server package and the sshd_config file before it manages the sshd service.

service { 'sshd':
  ensure  => running,
  require => [
    Package['openssh-server'],
    File['/etc/ssh/sshd_config'],
  ],
}

package { 'openssh-server':
  ensure => present,
  before => Service['sshd'],
}

file { '/etc/ssh/sshd_config':
  ensure => file,
  mode   => '0600',
  source => 'puppet:///modules/sshd/sshd_config',
  before => Service['sshd'],
}

Chaining arrows

You can create relationships between resources or groups of resources using the -> and ~> operators.

The ordering arrow is a hyphen and a greater-than sign (->). It applies the resource on the left before the resource on the right.

The notifying arrow is a tilde and a greater-than sign (~>). It applies the resource on the left first. If the left-hand resource changes, the right-hand resource refreshes.

In this example, Puppet applies configuration to the ntp.conf file resource and notifies the ntpd service resource if there are any changes.
File['/etc/ntp.conf'] ~> Service['ntpd']
Note: When possible, use relationship metaparameters, not chaining arrows. Metaparameters are more explicit and easier to maintain. See the Puppet language style guide for information on when and how to use chaining arrows.

Operands

The chaining arrows accept the following kinds of operands on either side of the arrow:

  • Resource references, including multi-resource references.
  • Arrays of resource references.
  • Resource declarations.

  • Resource collectors.
You can link operands to apply a series of relationships and notifications. In this example, Puppet applies configuration to the package, notifies the file resource if there are changes, and then, if there are resulting changes to the file resouce, Puppet notifies the service resource:
Package['ntp'] -> File['/etc/ntp.conf'] ~> Service['ntpd']
Resource declarations can be chained. That means you can use chaining arrows to make Puppet apply a section of code in the order that it is written. This example applies configuration to the package, the file, and the service, in that order, with each related resource notifying the next of any changes:
# first:
package { 'openssh-server':
  ensure => present,
} # and then:
-> file { '/etc/ssh/sshd_config':
  ensure => file,
  mode   => '0600',
  source => 'puppet:///modules/sshd/sshd_config',
} # and then:
~> service { 'sshd':
  ensure => running,
  enable => true,
}
Collectors can also be chained, so you can create relationships between many resources at one time. This example applies all Yum repository resources before applying any package resources, which protects any packages that rely on custom repositorie :
Yumrepo <| |> -> Package <| |>

Capturing resource references for generated resources

In Puppet, the value of a resource declaration is a reference to the resource it creates.

This is useful if you're automatically creating resources whose titles you can't predict: use the iteration functions to declare several resources at once or use an array of strings as a resource title. If you assign the resulting resource references to a variable, you can then use them in chaining statements without ever knowing the final title of the affected resources.

For example:

  • The map function iterates over its arguments and returns an array of values, with each value produced by the last expression in the block. If that last expression is a resource declaration, map produces an array of resource references, which you could then use as an operand for a chaining arrow.
  • For a resource declaration whose title is an array, the value is itself an array of resource references that you can assign to a variable and use in a chaining statement.

Cautions when chaining resource collectors

Chains can create dependency cycles.
Chained collectors can cause huge dependency cycles; be careful when using them. They can also be dangerous when used with virtual resources, which are implicitly realized by collectors.
Chains can break.
Although you can usually chain many resources or collectors together (File['one'] -> File['two'] -> File['three']), the chain can break if it includes a collector whose search expression doesn't match any resources.
Implicit properties aren't searchable.
Collectors can search only on attributes present in the manifests; they cannot see properties that are automatically set or are read from the target system. For example, the chain Yumrepo <| |> -> Package <| provider == yum |>, creates only relationships with packages whose provider attribute is explicitly set to yum in the manifests. It would not affect packages that didn't specify a provider but use Yum because it's the operating system's default provider.

Reversed forms

Both chaining arrows have a reversed form (<- and <~). As implied by their shape, these forms operate in reverse, causing the resource on their right to be applied before the resource on their left. Avoid these reversed forms, as they are confusing and difficult to notice.

The require function

Use the require function to declare a class and make it a dependency of the surrounding container.

For example:
class wordpress {
  require apache
  require mysql
  ...
}

The above example causes every resource in the apache and mysql classes to be applied before any of the resources in the wordpress class.

Unlike the relationship metaparameters and chaining arrows, the require function does not have a reciprocal form or a notifying form. However, you can create more complex behavior by combining include and chaining arrows inside a class definition. This example notifies and restarts every service in the apache::ssl class if any of the SSL certificates on the node change:
class apache::ssl {
  include site::certificates
  Class['site::certificates'] ~> Class['apache::ssl']
}