Manifests & the DSL

Declarative code and ordering.

Intermediate12 min · lesson 3 of 12

A manifest is a .pp file of Puppet DSL — resources plus the language around them (variables, conditionals, functions, relationships). The DSL is declarative but real: it has typed variables, selectors and case statements, iteration, and data types. The art is using that expressiveness to describe state clearly while keeping the declaration honest — the language is there to parameterize the model, not to script imperative steps.

web.pp
$worker_processes = 4
package { 'nginx': ensure => installed }
file { '/etc/nginx/nginx.conf':
ensure => file,
content => epp('nginx/nginx.conf.epp', { 'workers' => $worker_processes }),
require => Package['nginx'], # ordering: file after package
notify => Service['nginx'], # signal: reload on change
}
service { 'nginx': ensure => running, enable => true }

Relationships and the four metaparameters

Ordering and signalling are expressed with four metaparameters: require (apply after), before (apply before), notify (apply before, and signal on change), subscribe (apply after, and react to the other’s change). require/before are pure ordering; notify/subscribe add the refresh signal that reloads a service when its config changes. These relationships build the dependency graph Puppet applies — mastering them is mastering Puppet ordering.

chain
# the arrow syntax is shorthand for the same relationships
Package['nginx'] -> File['/etc/nginx/nginx.conf'] ~> Service['nginx']
# ordering (->) notify (~>)
Declare dependencies, not just source order
Puppet needs the require/before/notify relationships to know that the config file must exist before the service starts and that a config change must reload the service. Omit them and Puppet may apply resources in an order that starts a service before its config is present, or fails to reload after a change. Explicit relationships are not optional decoration — they are how the model actually converges correctly.