cheat sheet

every tl;dr in order · ~10 min to skim the whole course

1 · Orientation

1 · What Ansible is & isn't
  • Ansible is declarative: you state the end state, modules work out the how — Bicep thinking, not PowerShell.
  • Push-based and agentless, with no state file — "changed" is computed fresh against the real machine each run.
  • Bare shell tasks drag it back to scripting. Reach for a purpose-built module first.
2 · Agentless, push-based
  • The control node runs Ansible and connects OUT to managed nodes — no agent, daemon or service on targets.
  • Each task copies a module to the node, executes it, removes it. Only registered vars and facts survive.
  • The control node cannot be native Windows. Linux targets speak SSH; Windows targets WinRM, SSH or PSRP.
3 · ansible-core vs the community package
  • ansible-core = the engine plus the ansible.builtin collection only. Minimal by design.
  • The ansible community package = core plus a big curated bundle of collections — batteries included.
  • Two version tracks: each community major pins one core series, and only the latest major is maintained.
4 · Collections & FQCN
  • Since Ansible 2.10, modules live in collections — versioned packages under a namespace.
  • FQCN is the full path: ansible.builtin.copy, not copy. Write it always.
  • Old tutorials use bare names because they predate the split. That is how you date them.

2 · Setup

5 · Installing a control node
  • pip install ansible (core + 85+ collections) or ansible-core (engine only); distro packages exist too.
  • The control node needs a supported Python — policy is the three most recently released Python versions.
  • No native Windows control node. WSL works — but the two official guides contradict each other about it.
6 · ansible.cfg & config precedence
  • Every run reads ONE config file: ANSIBLE_CONFIG → ./ansible.cfg → ~/.ansible.cfg → /etc/ansible/ansible.cfg.
  • First file found wins — the search stops there. Nothing merges.
  • Best practice: a project-root ansible.cfg committed to Git, so everyone runs with identical settings.
7 · Your first ad-hoc command
  • ansible <target> -m <module> runs one module against some hosts, right now. That is an ad-hoc command.
  • Use it for quick checks and one-offs: ping a group, run uptime, gather a fact.
  • Anything repeatable is playbook territory (unit 4) — ad-hoc is a probe, not configuration.

3 · Inventory

8 · Inventory: INI and YAML
  • The inventory is the file naming every host Ansible manages, sorted into named groups.
  • Two formats — INI and YAML — describe the same thing; parent groups nest via children.
  • ansible-inventory --graph shows what Ansible actually parsed. Trust the graph, not the file.
9 · group_vars & host_vars
  • group_vars/ and host_vars/ sit next to your inventory and auto-load by group and host name.
  • Environment config lives here — per group in group_vars, pinned to one machine in host_vars.
  • group_vars/all.yml hits every host in the inventory. Keep it minimal.
10 · Patterns, --limit & per-env inventories
  • Patterns pick hosts at run time: all, web*, web:&staging (in both), web:!db (web minus db).
  • --limit narrows any run to the hosts you name — the re-run and debugging flag.
  • One inventory directory per environment is the guardrail that stops a staging run touching prod.
11 · Dynamic inventory & plugins
  • Dynamic inventory = a host list generated at run time by a plugin querying an API, not a static file.
  • Inventory plugins pull from cloud sources and CMDBs, and run on the control node like every plugin.
  • Static files suit estates you control by editing the file; dynamic suits estates whose truth lives elsewhere.

4 · Playbooks

12 · Playbook anatomy
  • A playbook is a list of plays; a play targets hosts and holds tasks; each task calls one module.
  • hosts: takes a lesson-10 pattern; -i picks the inventory that resolves it — same playbook, any environment.
  • Read the output per task: ok means already in the desired state, changed means Ansible altered something.
13 · YAML pitfalls & the quoting rule
  • Indentation is structure, and it is spaces only — a tab is a parse error, not a style choice.
  • A value that STARTS with {{ }} must be quoted, because a bare { opens YAML inline-dict syntax.
  • Unquoted yes/no/true/false all become booleans — quote them when you mean the literal word.
14 · Modules, plugins & collections
  • A module is a unit of work. Ansible ships it to the managed node, runs it, deletes it.
  • A plugin extends the engine itself and always runs on the control node — it never leaves home.
  • A collection is the shipping container: modules, roles and plugins packaged under one namespace.
15 · Registering output & debug
  • register: captures a task's full result dict into a named variable — the only state between tasks.
  • Inspect .stdout, .rc and .changed; print them with ansible.builtin.debug (msg or var).
  • register + debug is the everyday inspection loop: run, print, read, adjust.

5 · Logic

16 · Variables & the precedence that matters
  • The daily ladder, low to high: role defaults → inventory vars → role vars → set_fact → extra vars (-e).
  • Tunables in defaults/, environment config in group_vars/, internal constants in vars/. -e only on purpose.
  • Never pass secrets with -e — they leak into logs. When the wrong value wins, -vvv shows what each task used.
17 · Facts, set_fact & caching
  • Facts = per-host system data (OS, IPs, memory), auto-gathered by the setup module into ansible_facts.
  • gather_facts: false skips the survey; fact caching (jsonfile/redis) reuses results across runs.
  • set_fact writes your own runtime facts; /etc/ansible/facts.d adds custom facts on the node itself.
18 · Conditionals with when
  • when: takes a bare Jinja2 expression — no {{ }}. Wrapping the condition in braces is the classic mistake.
  • Condition on facts or registered fields (.rc, .changed); a false condition reports skipping, not failure.
  • A YAML list under when: means AND; combined with loop, the condition is evaluated per item.
19 · Loops, and the legacy with_*
  • loop: runs one task once per list element; the current element lands in the item variable.
  • with_* is legacy, not deprecated — it still works and ansible-lint only warns. Write loop: in new code.
  • loop_control fixes noisy output: label picks what each status line prints.
20 · Handlers, notify & listen
  • notify: queues a handler — a task that runs only when the notifying task reports changed.
  • Queued handlers run once, at the end of the play, however many tasks notified them.
  • listen: turns the notify string into a topic several handlers can subscribe to.
21 · Blocks & error handling
  • A failed task drops that host from the play — every other host carries on. Containment is per host.
  • failed_when redefines failure from the result; ignore_errors just barrels past a real one.
  • block groups tasks; rescue runs on failure, always runs regardless — try/catch/finally.

6 · Making it real

22 · Idempotency, deeply
  • Modules check current state and act only on the difference — re-runs converge, ending changed=0.
  • command and shell always execute and always report changed — fix with creates:, removes:, changed_when:.
  • The working test: run the playbook twice — an idempotent second run ends all ok, changed=0.
23 · Jinja2 templating & filters
  • template renders a .j2 file with each host's variables on the control node; copy ships bytes verbatim.
  • A filter transforms a value inside {{ }} via a pipe — default() and join are the everyday pair.
  • {{ }} prints, {% %} controls, | transforms — that triad reads any .j2 file you will meet.
24 · Roles: structure, defaults vs vars
  • A role packages tasks, handlers, templates, files and vars in a fixed layout; every main.yml auto-loads.
  • defaults/ holds user-tunable knobs (lowest precedence); vars/ holds internal constants (high).
  • Roles never name hosts — playbooks orchestrate roles against hosts. And a role is not a collection.
25 · import vs include
  • import_tasks/import_role are static: resolved at parse time. include_tasks/include_role: at runtime.
  • Default to import for parse-time checking; use include for variable filenames, loops, per-host paths.
  • Bare include: was removed in ansible-core 2.16 — playbooks still using it fail to parse.
26 · Galaxy, requirements.yml & pinning
  • ansible-galaxy installs collections and roles; requirements.yml is the manifest a project commits.
  • One command restores every dependency: ansible-galaxy install -r requirements.yml.
  • Pin versions — unpinned installs grab whatever is latest that day, and machines drift apart.

7 · Secrets & scale

27 · Ansible Vault & vault IDs
  • ansible-vault encrypts secrets at rest so they can live in Git; encrypt, decrypt, edit, view are the verbs.
  • Encrypt whole var files or single values (!vault); unlock runs with --ask-vault-pass or a password file.
  • Vault IDs label multiple keys, so dev and prod secrets can use different passwords in one run.
28 · Strategies, serial & delegation
  • linear (default) marches every host through a task before the next starts; free lets each host race ahead.
  • serial: 1 turns a play into a rolling update — the whole play finishes on one batch before the next begins.
  • delegate_to runs a task on a different host; run_once runs it a single time for the whole play.
29 · Run control: check, diff, tags, limit
  • --check dry-runs the playbook: modules report what would change without changing anything.
  • --diff adds line-by-line file diffs; tags: plus --tags runs a named slice of the tasks.
  • The pre-prod ritual: --syntax-check, --list-tasks, --check --diff, then the real run.

8 · Windows track

30 · Windows connections: WinRM, PSRP, SSH
  • Three plugins reach Windows: winrm, psrp (both ride WinRM) and ssh — chosen per host in inventory.
  • WinRM listens on 5985 (HTTP) / 5986 (HTTPS); unencrypted channels are refused, HTTPS is recommended.
  • SSH is officially supported since core 2.18 but needs OpenSSH 7.9+ — in practice Server 2022 or newer.
31 · The WinRM auth matrix
  • WinRM offers five auth options — Basic, Certificate, Kerberos, NTLM, CredSSP — differing on four properties.
  • Kerberos is the official recommendation in a domain; Basic and NTLM only over HTTPS for local accounts.
  • You pick with ansible_winrm_transport — or ansible_psrp_auth, which adds a negotiate option.
32 · Setting up a Windows target
  • Server 2016 / Windows 10 ship PowerShell 5.1 — no bootstrap needed on any current Windows target.
  • ConfigureRemotingForAnsible.ps1 lives on in tutorials, but official docs now warn against using it.
  • Modern setup: Enable-PSRemoting, explicit firewall rule, token filter policy, HTTPS listener, win_ping.
33 · Windows collections & modules
  • Windows modules live in ansible.windows (core) and community.windows (extended) — not ansible.builtin.
  • Your playbook habits transfer; module names don't — copy becomes ansible.windows.win_copy.
  • win_chocolatey is NOT in ansible.windows — it ships in the vendor collection chocolatey.chocolatey.
34 · become, runas & Windows paths
  • On Windows, become means become_method: runas — a fresh logon as become_user, not a sudo wrapper.
  • become also bypasses WinRM restrictions (WUA, DPAPI, non-interactive limits) — key for lesson 35.
  • Double-quoted "C:\temp" turns \t into a tab. Single-quote Windows paths and backslashes stay literal.
35 · The double-hop problem
  • WinRM hands the target a network logon: proof of who you are, but no credentials to pass onward.
  • Any task reaching a second server — share, AD, SQL — dies with Access is denied: the double hop.
  • Three fixes: Kerberos delegation, CredSSP, or become with explicit credentials.

9 · Workplace ecosystem

36 · Repo structure & conventions
  • The standard repo: ansible.cfg at root, inventories/<env>/, site.yml, roles/, two requirements.yml.
  • One inventory directory per environment makes cross-env accidents physically impossible.
  • Day one in a strange repo, read: ansible.cfg → inventories/ → site.yml → roles/.
37 · ansible-lint & yamllint
  • ansible-lint with profile: production — the strictest preset — is the bar real repos hold PRs to.
  • yamllint catches indentation and line-length slips; ansible-lint catches Ansible-specific bad practice.
  • Every skip in .ansible-lint needs a documented reason — undocumented skips get flagged in review.
38 · Molecule, conceptually
  • Molecule is the standard role test harness: boot a container, converge, check idempotence, verify, destroy.
  • The idempotence phase is lesson 22's run-twice test, automated: the second run must report changed=0.
  • Teams run it in CI on every PR. Linting is a separate step, not part of the default test sequence.
39 · AWX, AAP & the retired Tower name
  • AWX is the free open-source upstream; AAP is Red Hat’s supported enterprise product.
  • “Tower” is a retired name — last version 3.8. When colleagues say it, they usually mean AAP.
  • Both give job templates, workflows, surveys, credentials, RBAC, schedules and a /api/v2/ REST API.
40 · Execution environments & navigator
  • An EE is a container image: ansible-core + collections + their Python/system deps, built by ansible-builder.
  • ansible-navigator runs playbooks inside an EE by default — the image tag pins your whole runtime.
  • Inside an EE, localhost is the container: files "saved locally" vanish when the container is removed.
41 · Jenkins + Ansible
  • Two ways in: shell out to ansible-playbook on the agent, or the Jenkins plugin's ansiblePlaybook step.
  • The pipeline shape: checkout scm, ansible-galaxy install -r requirements.yml, then ansiblePlaybook.
  • Secrets — SSH keys, vault passwords — live in the Jenkins credential store, referenced by ID.
42 · Jargon, debugging & interview prep
  • Debug a broken run in a fixed order: reachability, inventory, syntax, dry run, narrow, inspect.
  • The day job is patching, packages/services, templated config, users, onboarding hosts, deploys.
  • Mid-level interviews test concepts and scenarios, not custom module authoring. RHCE is Linux-only.