RH294 Ch 7: Deploying Files with Templates and File Modules
Most configuration work is putting the right file, with the right content and permissions, on the right host. Ansible gives you a small set of modules for that, and choosing the right one is half the job.
Whole files: copy and template. ansible.builtin.copy sends a file from the project (src:) or writes literal text (content:). ansible.builtin.template does the same with a Jinja2 file that is rendered per host first. Both take owner, group and mode — always quote modes ('0640'), or YAML reads 0640 as an octal number.
yaml - name: Message of the day ansible.builtin.template: src: templates/motd.j2 dest: /etc/motd mode: '0644'
Jinja2 basics. {{ expression }} prints a value, {% ... %} is logic, { ... } is a comment. Facts are available as ansiblefacts['hostname'], ansiblefacts['memtotalmb'] and so on. Loops and conditionals work inside the template:
jinja {% for h in groups['all'] %} {{ hostvars[h]['ansiblefacts']['defaultipv4']['address'] }} {{ hostvars[h]['ansiblefacts']['fqdn'] }} {{ h }} {% endfor %}
hostvars[h] only holds another host's facts if that host was in a play that gathered them. That is why a "hosts file on dev only" task is written as a play on all with when: inventoryhostname in groups['dev'], not a play on dev.
Editing in place. ansible.builtin.lineinfile manages one line: regexp finds the line to replace, line is the new text, state: absent removes it. ansible.builtin.blockinfile manages several lines between BEGIN ANSIBLE MANAGED BLOCK and END ANSIBLE MANAGED BLOCK markers, so re-running replaces the block instead of appending it again.
Files, directories and links. ansible.builtin.file sets attributes and creates things: state: directory, state: touch, state: link (with src = target, dest = link name), state: absent. Use ansible.builtin.stat to inspect a file, and fetch to pull one back to control.
Common exam mistakes - Unquoted modes like mode: 0644 or 2775 without quotes. - Putting a template in the wrong directory: in a playbook, src is relative to templates/ next to the playbook; in a role, to the role's templates/. - Using command: echo ... file — it is not idempotent and does not even work in command. - Forgetting that a lineinfile without regexp adds a new line instead of replacing the old one. - Swapping src and dest for symbolic links.