Articles
Puppet Interview Questions: Catalogs, Resource Ordering, and Refresh Events
Practice Puppet interview questions with catalog compilation, resource ordering, refresh events, guarded execs, no-op limits, and dependency failure evidence.
Puppet interview questions become easier when you stop treating a manifest as a shell script. A catalog describes desired resources and their relationships. The agent still has to inspect the machine, make eligible changes, and handle any resulting refreshes. A file appearing before a service in the code does not fully explain whether that service will consume new configuration.
This guide uses official Puppet Core documentation, displaying version 9.1.0 when checked October 6, 2026. The manifests and run ledgers are original Linux examples. Local Python checks exercise graph and event assumptions; they do not execute Puppet or certify a service provider. No candidate report establishes these exercises as questions from a particular employer.
Start with Return a Package Build Order. Explain which edges establish prerequisites, then ask what additional behavior a notification edge promises.
What does a compiled catalog establish?
Official facts: a catalog specifies desired resources for a node and can include ordering dependencies. A primary server resolves manifests with agent-provided and external data; puppet apply compiles and applies locally. Compilation and application are different stages. Catalog compilation.
For our hypothetical exampled service, compilation can produce the intended package, file, and service declarations. It does not demonstrate that a package repository is reachable, that the local file is writable, or that a restart command succeeds.
In an interview, separate “the intended resource is in the catalog” from “the resource converged on this node.” Ask for the selected environment and relevant facts before debugging an apparent omission. A manifest in a repository is not evidence that the affected node received those declarations.
Our troubleshooting inference is to locate the first missing proof: catalog membership, actual dependency graph, resource application result, or application behavior. Each boundary can fail independently, so a successful compile should narrow the investigation rather than close it.
Does declaration order remove the need for relationships?
Official facts: unrelated resources normally follow manifest order, while explicit and automatic relationships can change that order. Explicit dependencies should express necessary prerequisites. Relationships can refer to resources declared later. Relationships and ordering.
Suppose two modules separately manage a package and its configuration. Their present textual order is an incidental arrangement; our intended contract is that the package must be available before configuring its service. Encode that requirement so refactoring the module structure does not erase the design.
Automatic relationships also matter. Do not assume the graph contains only arrows visible in one file. Inspect the effective relationships for the affected resources, including those established by types or by surrounding classes.
A useful explanation names the failure the edge prevents: “The configuration requires the installation prerequisite, and the service requires a usable configuration.” Merely saying “Puppet is declarative” does not reveal whether the actual graph expresses either condition.
How do require and subscribe differ?
Official facts: require and before establish ordering; notify and subscribe add refresh behavior when the upstream resource changes. -> is an ordering arrow and ~> is a notifying arrow. A notification therefore includes an ordering relationship. Metaparameter reference, relationships and ordering.
For our exercise, File[...] -> Service[...] promises that Puppet manages the file first. It does not express the requirement to restart a running process after a configuration change. Changing that edge to ~> adds the missing event relationship.
Direction is another common mistake. A service subscribing to a file depends on that file; a file notifying a service expresses the same upstream-to-downstream intent from the other declaration. Describe the source and recipient before choosing syntax.
Use one clear relationship representation in the answer. Repeating equivalent arrows and metaparameters makes it harder to see the intended owner of the restart without improving this exercise's contract.
Trace a package-file-service manifest
Assume our fictional Linux package provides /etc/exampled.conf and a service named exampled. The selected provider supports starting and restarting it. These assumptions are part of the fixture; the snippet is source-reviewed, not an instruction to apply an invented package on a real host.
package { 'exampled':
ensure => present,
}
file { '/etc/exampled.conf':
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => "workers=4\n",
require => Package['exampled'],
notify => Service['exampled'],
}
service { 'exampled':
ensure => running,
enable => true,
require => Package['exampled'],
}
Our run ledger distinguishes ordinary state enforcement from refresh-triggered work. The exercise starts with an installed package unless a row states otherwise.
| Observed state or modification | Expected explanation under our assumptions |
|---|---|
| Service running; file has workers=2 | File changes to workers=4; notification requests a service refresh. |
| Next run: service running; file already correct | No file change means no file-triggered refresh. |
| Service stopped; file already correct | Ensure-running requires a start independently of a file event. |
| File changes, but notify is replaced with ordering only | Ordering remains; a file-triggered restart is no longer requested. |
| Package application fails on an uninstalled node | Dependent file and service cannot be treated as successfully applied. |
Do not invent an exact total of start and restart commands for a first installation. Our table explains causal obligations; the provider and initial state determine the concrete operations. That distinction prevents a neat diagram from becoming an unsupported execution guarantee.
Why can a running service still be using old configuration?
Official fact: a service refresh restarts the service; its concrete restart behavior depends on the platform and configured commands. ensure => running and startup enablement express different properties. Service resource.
Our hypothetical daemon reads configuration at startup. A report showing the file changed and the process stayed running does not prove it adopted four workers. Check whether the event relationship exists and whether the refresh succeeded, then inspect application evidence such as the effective configuration or worker count.
Suppose a restart completes but the process still exposes two workers. Possible explanations in our fixture include reading another file, a command targeting another service instance, or configuration rejected by the daemon. Investigate those conditions instead of adding another notification reflexively.
Likewise, enabling startup is not proof that the process is running now. A good answer follows the specific observed discrepancy: desired boot behavior, current process state, and active configuration are related but separate assertions.
When does a refreshonly exec run?
Official facts: refreshonly => true makes an exec event-driven. An ordering requirement alone cannot trigger it. Guards such as onlyif, unless, or creates still determine whether execution is needed. Exec resource.
Our second asset is a route-index rebuild. Assume the package, routes file, and index directory are already declared elsewhere. The fictional helper's needs-rebuild subcommand returns zero only when the derived index is missing or stale; its check is read-only. Its build subcommand safely replaces the output.
exec { 'rebuild-exampled-index':
command => ['/usr/local/bin/example-index', 'build'],
onlyif => [['/usr/local/bin/example-index', 'needs-rebuild']],
refreshonly => true,
subscribe => File['/etc/exampled.routes'],
require => [Package['exampled'], File['/var/lib/exampled']],
}
The index directory prerequisite prevents a build before its destination exists. The subscription supplies a different condition: a changed routes resource requests work. Our model intentionally requires both an event and a satisfied guard in this ordinary, non-noop scenario.
| Event during the run | Guard says rebuild needed | Our expected main-command outcome |
|---|---|---|
| No | Yes | No event-driven build. |
| Yes | No | Guard blocks the build. |
| Yes | Yes | Build is eligible. |
The first row exposes a recovery gap: deleting only the derived index does not necessarily change the routes file. If the index must be repaired whenever missing, event-only design is insufficient. Choose ordinary guarded convergence or a suitable custom resource instead of pretending the subscription detects every form of drift.
Is every exec refresh exactly one command execution?
Official fact: exec refresh behavior is special. A previously run exec can execute up to twice after an event, depending on guards and the refresh attribute. A guard that prevents execution remains relevant when an event arrives. Exec resource.
Our practical recommendation is to examine the exact exec definition, its earlier activity, its current guards, and any alternate refresh command. Do not copy the service's mental model into an arbitrary exec.
In the index exercise, creates => '/var/lib/exampled/index' would be an inappropriate replacement for a freshness check if that file persists after later source changes. Existence answers “was an output created?”; it does not answer “does this output represent the latest routes?”
We also assume the builder itself tolerates retry. Event-driven scheduling cannot make a destructive shell action repeatable. Explain the builder's output contract and failure handling before claiming that a successful Puppet run makes the derived artifact correct.
What does no-op prove, and what can still execute?
Official facts: a no-op resource reports intended changes without applying them or forwarding simulated refresh events. Explicit resource-level noop values are not overridden by the global setting. Metaparameter reference.
Official exec caveat: guard commands can execute during no-op checks. The exec reference also describes a special case where noop => true receives an event from a non-noop resource and executes once, potentially using its alternate refresh command. Exec resource.
For our fully no-op file/index scenario, a simulated routes change cannot establish that the builder or daemon has worked. It provides useful intended-change evidence; real application behavior remains untested.
Before interpreting a no-op result, inspect resource overrides and guard implementations. Our read-only checker is safe to evaluate as a check; replacing it with a command that mutates the index would invalidate that assumption. Report the boundary precisely instead of calling no-op an entirely inert execution environment.
How do missing resources, cycles, and failed prerequisites differ?
Official facts: referencing an undeclared dependency fails compilation. A dependency cycle can compile but prevents catalog application. If a prerequisite fails while applying, downstream resources are skipped; unrelated resources can continue. Relationships and ordering.
Use three different repairs. If our service references a nonexistent file title, correct the reference or include the required declaration. If file and service depend on one another, remove the unjustified reverse edge rather than retrying the same cycle. If package installation fails, diagnose that failure before blaming the skipped service.
Official resource guidance also rejects duplicate resource identities, including conflicting declarations for the same managed resource. Removing a declaration does not itself remove the underlying object. Resources.
For a repair, preserve the failed run's environment, catalog identity, affected edges, and earliest error. Our original acceptance checks then ask whether the intended resource is present, prerequisite succeeds, file content matches, refresh occurs only when appropriate, and the daemon exposes the expected behavior. A second unchanged run tests stability; it does not erase missing first-run evidence.
Sources and Further Reading
- Puppet: Catalog compilation
- Puppet: Resources
- Puppet: Relationships and ordering
- Puppet: Metaparameter reference
- Puppet: Exec resource
- Puppet: Service resource
Documentation checked October 6, 2026. Validate source-reviewed examples against the specified Puppet version, platform, and provider before treating predicted behavior as execution evidence.