Chapter 11: Comprehensive Review

Ansible final review cheat sheet

The whole course on one page: a sentence per chapter, the commands and file formats you reach for most, the module for each common job, and flashcards that mix every chapter.

The course in nine sentences

  1. Ansible connects over SSH from one control node, needs nothing installed on managed hosts but Python, and describes the state you want rather than the steps.
  2. A project is a directory with its own ansible.cfg and inventory; plays in a playbook map groups of hosts to tasks that call modules.
  3. Variables live in the inventory, group_vars, host_vars, plays and files; facts describe each host; Ansible Vault encrypts what must stay secret.
  4. Loops, conditions, handlers and blocks decide what runs, how often, and what happens when something fails.
  5. Templates turn one Jinja2 file into a different file on each host; file modules manage content, ownership, modes and SELinux contexts.
  6. Host patterns select exactly the hosts you mean; imports and includes split large playbooks into reusable pieces.
  7. Roles package tasks, defaults, templates and handlers; collections deliver roles and modules, including the system roles.
  8. When a run fails, find the stage first (parse, connect, escalate, run), then use syntax checks, verbosity, check mode and diffs.
  9. One module per administration job, for software, users, services and schedules, storage and networking, keeps every task idempotent.

Cheat sheet

Project

[defaults]
inventory = ./inventory
remote_user = devops
roles_path = ./roles:/usr/share/ansible/roles
collections_path = ./collections:~/.ansible/collections:/usr/share/ansible/collections

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
[dev]
servera.lab.example.com

[prod]
server[c:d].lab.example.com

[webservers:children]
prod
$ ansible-navigator inventory -m stdout --graph
$ ansible all -m ansible.builtin.ping
$ ansible-config dump --only-changed
$ ansible webservers -m ansible.builtin.command -a 'uptime'

Running

$ ansible-navigator run -m stdout site.yml --syntax-check
$ ansible-navigator run -m stdout site.yml --check --diff
$ ansible-navigator run -m stdout site.yml -v          # -vvv for connections
$ ansible-navigator run -m stdout site.yml --list-tasks
$ ansible-navigator run -m stdout site.yml --start-at-task "NAME"
$ ansible-navigator run -m stdout site.yml --step
$ ansible-navigator run -m stdout site.yml --limit servera.lab.example.com
$ ansible-navigator run -m stdout site.yml --vault-password-file vault-pass
$ ansible-doc -s MODULE        # task skeleton
$ ansible-doc MODULE           # full page, EXAMPLES at the end

Task control

- name: Web servers are configured
  hosts: webservers
  vars_files:
    - vars/users.yml
  tasks:
    - name: Users for this environment exist
      ansible.builtin.user:
        name: "{{ item['name'] }}"
      loop: "{{ users }}"
      when: item['env'] in group_names

    - name: Settings are in place
      ansible.builtin.template:
        src: templates/site.conf.j2
        dest: /etc/httpd/conf.d/site.conf
      notify: restart httpd

    - name: Try, recover, clean up
      block:
        - ansible.builtin.command: /usr/local/bin/migrate
          register: out
          changed_when: "'migrated' in out.stdout"
          failed_when: "'ERROR' in out.stdout"
      rescue:
        - ansible.builtin.debug:
            msg: Migration failed, rolled back
      always:
        - ansible.builtin.file:
            path: /tmp/migrate.lock
            state: absent

  handlers:
    - name: restart httpd
      ansible.builtin.service:
        name: httpd
        state: restarted

Vault

$ ansible-vault create secret.yml
$ ansible-vault view secret.yml
$ ansible-vault edit secret.yml
$ ansible-vault encrypt vars.yml
$ ansible-vault decrypt vars.yml
$ ansible-vault rekey secret.yml
$ ansible-vault encrypt_string 'Secret123' --name db_password
password: "{{ db_password | password_hash('sha512', 'fixedsalt') }}"

Roles and collections

$ ansible-galaxy role init roles/NAME
$ ansible-galaxy role install -r roles/requirements.yml -p roles
$ ansible-galaxy role list
$ ansible-galaxy collection install -r collections/requirements.yml -p collections
$ ansible-galaxy collection list
---
- src: file:///home/student/review-roles/archives/acme.motd-1.0.tar.gz
  name: acme.motd
- src: https://git.example.com/roles/web.git
  scm: git
  version: main
  name: web
---
collections:
  - name: ansible.posix
    version: 1.5.4
  - name: community.general

One module per job

JobModule or role
Install, update, remove packagesansible.builtin.dnf
Add a repository and its keyansible.builtin.yum_repository, ansible.builtin.rpm_key
Users, groups, SSH keysansible.builtin.user, ansible.builtin.group, ansible.posix.authorized_key
Servicesansible.builtin.service, ansible.builtin.systemd
Firewallansible.posix.firewalld
Files: create, copy, edit a line, a blockfile, copy, lineinfile, blockinfile (all ansible.builtin)
A file per host from a templateansible.builtin.template
SELinux booleans and file contextsansible.posix.seboolean, community.general.sefcontext
Scheduled jobsansible.builtin.cron, ansible.posix.at
Reboot and waitansible.builtin.reboot
Partitions, LVM, file systems, mountscommunity.general.parted, lvg, lvol, filesystem, ansible.posix.mount
Network connectionscommunity.general.nmcli, or the network system role
Time, SELinux, storage, network in one roleredhat.rhel_system_roles.timesync, .selinux, .storage, .network
Test a web pageansible.builtin.uri
Show a valueansible.builtin.debug
Which ansible.cfg wins?
ANSIBLE_CONFIG, then ./ansible.cfg, then ~/.ansible.cfg, then /etc/ansible/ansible.cfg. Only one is read.
A group made of other groups?
`[parent:children]` followed by the child group names.
List the groups of the current host?
`group_names`, a magic variable.
All hosts in a group, from any host?
`groups['NAME']`
Another host’s facts?
`hostvars['HOST']['ansible_facts']`
Keep a password task idempotent?
A fixed salt in `password_hash`, or `update_password: on_create`.
Run a task for each item, only where it applies?
`loop` plus a `when` that refers to `item`.
When does a handler run?
Once, at the end of the play, if any task notified it and changed.
Ignore a failure but still see it?
`ignore_errors: true`, or a `block` with `rescue`.
Hosts in web and prod?
`web,&prod`
Static or dynamic reuse?
`import_tasks` is static; `include_tasks` is dynamic and can loop.
Role values meant to be overridden?
`defaults/main.yml`
Install a role from a local archive?
`src: file:///path/to/archive.tar.gz` and a `name`, in roles/requirements.yml.
Pin a collection version?
`version:` under the entry in collections/requirements.yml.
Preview changes without making them?
`--check --diff`
The disk exists on this host?
`when: "'sdb' in ansible_facts['devices']"`
Mount now and at every boot?
`ansible.posix.mount` with `state: mounted`
Prove a playbook is idempotent?
Run it twice; the second recap shows `changed=0`.

Where to go from here

Reset the servers and do each review lab again from the start, timed. Stop when you finish every lab well inside the time with the solutions closed.

The summaries of chapters 3 to 10 each end with a short timed drill. Work through all of them in one sitting, as one mixed session.

Take a working project, introduce one error, and have a friend do the same for you. Diagnosing a failure you did not cause is the fastest way to learn the error messages.

For every module in the table above, read the options and examples in ansible-doc. Most useful options are ones you have not needed yet.