puppet agent -t trigger a run: fetch facts, compile me, applypuppet agent -t --noop simulate, report drift, change nothingpuppet catalog compile build me on the masterfacter -p see the facts that parameterise mepuppet parser validate file.pp syntax-check a manifestpuppet resource service nginx introspect live state as Puppet sees itWhat I Am
I am the catalog: a compiled, node-specific directed graph of resources expressing desired state. I am not a script. I declare what should be true, never a sequence of imperative steps. Two runs of me on the same node produce the same end state because every resource is idempotent.
Declarative consequences
Order between resources is not implied by file position — it must be declared explicitly with relationships. The agent converges the node to my specification regardless of starting state.
Per-node, per-run
I am compiled fresh for one node from its facts plus shared code and data. Change the facts or the data, and a different catalog is born.
Resource Types & Providers
Every node in my graph is a resource: a type, a title, and a set of attributes describing desired state.
package { 'nginx':
ensure => installed,
}
service { 'nginx':
ensure => running,
enable => true,
require => Package['nginx'],
}
file { '/etc/nginx/nginx.conf':
ensure => file,
content => template('nginx/nginx.conf.erb'),
notify => Service['nginx'],
}
type { 'title': attr => value }providerensurepuppet describe servicepackage declaration converges on Debian or RHEL because providers map intent to local tooling.Manifests, Modules & the Code I'm Built From
Module layout
mymodule/
manifests/
init.pp # class mymodule
config.pp # mymodule::config
templates/
files/
data/ # module-level Hiera
hiera.yaml
metadata.json
Classes & defined types
A class is a singleton bundle of resources, declared once. A define is a reusable resource macro you can instantiate many times with different titles.
| Construct | Purpose | Cardinality |
|---|---|---|
class | Group resources, included once per node | Singleton |
define | Parameterised, repeatable resource group | Many |
node | Match a certname to classification | Per node |
include / contain | Declare a class into the catalog | — |
How I Am Compiled
The pipeline that produces me on the master:
1. Node classification2. Fact injection$facts and trusted data; they parameterise evaluation.3. Code evaluation4. Relationship & graph build5. Catalog outputif/case — only a fixed resource graph. Functions like generate run server-side, not on the node.Facter & the Trust Boundary
Facter discovers node facts (OS, networking, hardware) and presents them as input to my compilation. But facts are self-reported by the agent — a security boundary.
| Data source | Variable | Trust |
|---|---|---|
| Facter / custom facts | $facts['os']['family'] | Spoofable by the node |
| Cert-derived data | $trusted['certname'] | Validated from the SSL cert |
| Cert extensions | $trusted['extensions'] | Signed at cert issuance |
$trusted hash data, which derives from the agent's signed certificate.Relationships, Ordering & Refresh
Because I am declarative, edges in my graph are explicit. Metaparameters and chaining arrows build them.
require => Resource['x']before => Resource['x']notify => Service['x']subscribe => File['x']File['a'] -> Service['b']File['a'] ~> Service['b']