Articles
Chef DevOps Interview Questions: Convergence, Notifications, and Custom Resources
Trace Chef convergence, changed-resource notifications, and custom-resource state checks, with first-run and second-run evidence for interview answers.
For Chef DevOps interview questions, trace what changes on the node, which resource reports an update, and which action follows. A recipe that finishes successfully is not enough evidence of idempotency. A quiet second run does not prove that a stopped service will recover or that a failed restart will be retried.
This article separates official Chef documentation from original interview exercises and engineering recommendations. Execution examples use Chef Infra Client 18 documentation; current-value terminology also references the Client 19 glossary. The Ruby snippets are illustrative and syntax-checked locally, not executed against Chef, a service manager, or a production node. No candidate reports establish how frequently an employer asks these questions.
Explain the observable state before reaching for a restart or an unconditional shell command.
What does convergence actually prove?
Convergence is the work of bringing managed state toward its declared desired state. Idempotency concerns whether repeating the operation produces unnecessary changes once that state is satisfied. In an interview, name the state being compared: file contents, permissions, installed package version, service status, or an external system's configuration.
Official fact: Chef's cookbook execution documentation distinguishes building the resource collection from executing resources. Ordinary Ruby expressions and resource actions are therefore not interchangeable statements about when work happens. A file read written directly in a recipe can happen before the file-producing resource has converged.
Consider an original diagnostic question: a command downloads configuration, and a later Ruby expression reads it. Ask whether the download occurs during convergence and the read occurs earlier during recipe evaluation. Trace when the download and read happen; their written order alone is insufficient. Explain the execution context before proposing a timing fix.
Do not infer that every command becomes idempotent because it appears in a Chef recipe. An unconditional operation that appends a line or rotates a key has different repeat behavior from a resource that compares current and desired values. Describe the comparison that prevents repeated work, then show how a deliberate drift is repaired.
Trace one changed file and one delayed notification
Official fact: Chef documents the file resource for managing node files, including their content and permissions. Its common notification behavior links a resource update to another resource's action. For an already declared target such as the service below, delayed notifications queue its action for the end of the client run; immediate notifications run it when triggered.
The following original, source-reviewed recipe assumes the service already exists, its provider supports restart, the parent directory exists, and the client has suitable permissions. Those prerequisites are intentionally outside this small example.
service 'demo-agent' do
action :nothing
end
file '/etc/demo-agent.conf' do
content "mode=stable\n"
mode '0644'
action :create
notifies :restart, 'service[demo-agent]', :delayed
end
Here the service declaration supplies a notification target. The file resource owns the stated configuration. The example has one notifying resource and assumes the run reaches its delayed-action stage successfully; it is not a general proof about every combination of notifications and failures.
The original execution ledger makes the expected observations explicit:
| Starting state | File result under the assumptions | Notification consequence |
|---|---|---|
| File absent | Create the desired contents and mode; report an update | Queue the requested restart. |
| File already has the desired contents and mode | No file change is required | This file does not request another restart. |
Someone changes mode=stable to mode=experimental | Restore the desired contents; report an update | Queue the requested restart again. |
| File is correct but the service has stopped | File remains unchanged | This recipe does not request a restart merely because the service is stopped. |
Official fact: The service resource documentation lists :nothing as taking no action unless notified. If the actual requirement includes keeping the daemon running, specify and verify that requirement separately rather than assuming a file notification enforces it.
For the second run, check both the managed file and the relevant action evidence. “The exit code was zero” does not tell you whether the file changed, a restart happened, or an unrelated resource did work. Record whether this file changed and this service restarted on each run; an aggregate updated-resource count cannot answer both questions.
When should you use immediate rather than delayed actions?
Use an engineering inference based on the dependency: does later work require the service to have consumed the new configuration now, or can it wait until the end of the run? For this recipe, switching the timer changes the timing of the requested restart after a file update. It does not make an unchanged file report an update.
A delayed restart can suit a sequence of related configuration changes when the service does not need intermediate states. An immediate action may be necessary when a later operation depends on a refreshed daemon. Neither timer validates the configuration or verifies service health by itself. Describe those checks as separate responsibilities.
Official fact: Chef's common resource functionality documents a useful asymmetry: notifies raises an error when its referenced target resource is absent, while subscribes does not fail simply because its source is missing. A subscription listens for a source update; it does not perform the source's change.
That distinction matters in an original optional-component case. Suppose a monitoring service subscribes to a configuration resource that a conditional recipe never declares. A silent absence of the subscription source can explain the missing action. If that configuration is mandatory, allowing its absence may hide a broken dependency rather than offer useful flexibility.
In your answer, name the resource identity exactly, including its type and name. Check whether it is actually declared in the relevant context. Do not change the timer repeatedly when the true problem is a missing or mismatched target.
What changes inside a Unified Mode custom resource?
Official fact: Unified Mode compiles and converges a custom resource's action block in one pass, in its written order. It is the default from Client 18. Each called custom resource retains its own mode; the calling resource does not convert every nested resource or the entire recipe to a new global execution model.
For an original custom-action sketch, imagine that the action creates a local data file and then reads it to derive another resource's content. Under the documented Unified Mode behavior, the earlier declared resource can execute before the following Ruby read in that action. State the action's scope and installed version before explaining why the read is timely.
The scope is the important follow-up. A Ruby read outside the custom action does not become safe merely because some other resource uses Unified Mode. Likewise, code copied from an older custom resource may rely on deferred evaluation differently. Trace the producer and consumer in the actual execution context.
Avoid memorizing “compile and converge no longer exist” as an answer for all Chef code. Show which block is being discussed and what happens when it calls a resource using a different mode. A version-specific explanation is more useful than a blanket lifecycle slogan.
How should a custom resource load and compare state?
Official fact: Chef's custom resource glossary describes load_current_value for loading existing property values, current_value_does_not_exist! for an absent current resource, and converge_if_changed for comparing desired properties against those loaded values inside an action.
This original content-only teaching sketch separates observation from mutation. It omits permissions, parent-directory creation, ownership, and service management so the comparison remains visible. It is not a complete production file resource replacement.
unified_mode true
property :path, String, name_property: true
property :content, String, required: true
load_current_value do |desired|
if ::File.exist?(desired.path)
content IO.read(desired.path)
else
current_value_does_not_exist!
end
end
action :create do
converge_if_changed :content do
file new_resource.path do
content new_resource.content
action :create
end
end
end
The intended comparison has three cases: absent state requires creation; equal content requires no content update; different content requires correction. Loading the desired value as if it were the observed value would erase the difference. Omitting the observation and blindly writing on every call would make the comparison meaningless.
Now ask what this teaching sketch cannot detect. A file containing the right text but mode 0600 instead of required 0644 still has equal content. If permission management is part of the custom resource's contract, represent and compare that state or delegate it deliberately. Do not claim ownership of properties that your model never observes.
Observation failures also need a policy. A missing file and a permission-denied read are different conditions. Treating every exception as “resource absent” can lead to destructive or confusing retries. Preserve the actual failure, and decide whether the action should stop before any mutation.
Why can a rerun fail to recover a failed restart?
Consider an original failure trace, not an observed Chef run: the file update succeeds, its delayed restart is attempted, and that restart fails. At the next run, the file already matches its desired contents. The file comparison alone now provides no new change event to request the restart again.
This exposes two different states: desired configuration on disk and active configuration in the process. The first can be correct while the second remains old or unavailable. A recovery plan must identify the remaining mismatch rather than hoping a repeated file comparison will discover it.
An engineering recommendation is to preserve evidence of the failed action, inspect whether the daemon is running, and verify which configuration it has loaded. Then choose an explicit recovery action appropriate to that service. A restart may be necessary, but its safety and success criteria depend on the application's behavior and operating constraints.
Do not describe the recipe as an atomic transaction across file changes and daemon state. The new file can remain on disk after the daemon restart fails. Similarly, suppressing an error does not make the missing state correct. If the interview adds retry settings, discuss the particular resource/action being retried and its repeat safety.
For a realistic verification plan, exercise creation, an unchanged rerun, deliberate content drift, and a restart failure in a disposable environment. Check the file's contents and mode, the service's state, and the action logs after each case. Ruby syntax checks establish only that the snippets parse; they do not establish provider behavior, notifications, or recovery.
Practise the operational follow-ups
The aim is to connect a resource trace to rollout dependencies, observable health, and recovery boundaries.
| Question | Follow-up to practise |
|---|---|
| Deployment Window Scheduler: Allowed Minus Freeze Windows, Time Zones, Filters | Explain when a requested change may run and how you verify the constraint. |
| Explain CI/CD, Kubernetes delivery, and troubleshooting | Separate successful automation from the final service state. |
| Design config rollout and click aggregation | Identify configuration ownership and rollout dependencies. |
| Respond to a Reliability Regression Shortly After Deployment | Preserve the evidence needed to select a recovery action. |
| Discuss Terraform, Infrastructure as Code, and AWS Experience | Explain which tool owns which desired state. |
Start with one Site Reliability Engineer practice question, then walk through the file ledger aloud. Finish by changing one assumption: the file is correct, but the restart failed. A strong answer follows the remaining state mismatch and explains how you would verify recovery.