Skip to content

Interview Prep: Core Concepts

What is idempotency, and why does it matter operationally?

Short answer: Running the same operation multiple times produces the same end state as running it once — no duplicated side effects on repeat runs.

Detailed: Ansible modules follow a check-then-act pattern: compare current state to desired state, and only change what actually differs. This is what makes "just run the playbook again" a safe default in production instead of a gamble. Full mental model: Idempotency.

Common misconception: That playbooks are idempotent. They're not — modules are (or aren't); a playbook is only as idempotent as the modules its tasks call. A shell task inside an otherwise-idempotent playbook is still not idempotent.

Senior follow-up: "How would you audit an existing 300-task playbook for non-idempotent tasks without reading every line by hand?" — run it twice and diff the changed counts in the recap; any task reporting changed on the second run of an unmodified target is a candidate.

What is Ansible's variable precedence order, from highest to lowest?

Short answer: -e (extra vars) highest, role defaults/main.yml lowest, with task vars, block vars, role vars, set_fact/registered, play vars, host_vars, group_vars, inventory vars, and facts in between.

Detailed: Full order and the reasoning behind it (broad/overridable at the bottom, narrow/deliberate at the top): Variable Precedence.

Common misconception: That group_vars beats role vars/main.yml — it's the opposite; role vars (not defaults) outranks group_vars.

Senior follow-up: "Two roles are included in the same play and each defines a defaults/main.yml value for a same-named variable — which wins, and why is that a design smell?" — the last-included role's default typically applies in practice due to load order, but the real answer is that unnamespaced role variables colliding at all is the actual problem; see Role Variables and Interfaces.

What is the check-then-act pattern, and which layer implements it — the playbook or the module?

Short answer: The module. A playbook just calls modules in order; whether a given call is safe to re-run depends entirely on whether that module checks state before acting.

Detailed: See Modules for the mechanism, and Build a Custom Module for what implementing it actually looks like in code.

Senior follow-up: "You've written a custom module — what specifically makes it check-mode-safe, beyond declaring supports_check_mode=True?" — the code must explicitly branch on module.check_mode and skip the actual write; declaring support without honoring it is worse than not supporting it, because it looks safe and isn't.

What's the practical difference between command and shell?

Short answer: command runs a program directly with no shell involved — no pipes, redirects, or injection risk from shell metacharacters. shell runs the argument through /bin/sh, enabling shell features at the cost of injection risk.

Detailed: Full comparison, including raw and script, and a decision tree: Command vs. Shell vs. Raw vs. Script.

Common misconception: That either one is idempotent because it's "inside a playbook." Neither is, by default — both need creates/removes/changed_when to behave safely on a re-run.

Senior follow-up: "A shell task builds its command string from a variable that ultimately traces back to user input somewhere upstream — what's the actual risk, and how do you eliminate it, not just mitigate it?" — command injection; eliminate it by switching to command (no shell) or a real module, not by trying to sanitize the string.

Next

Continue to Architecture & Performance.