Chapter 6: Deploying Files to Managed Hosts

Ansible files and templates cheat sheet

The chapter on one page: what each file module is for, the template syntax in one place, and flashcards for quick revision.

The chapter in six sentences

Cheat sheet

Files

- ansible.builtin.file:             # attributes, directories, links, removal
    path: /srv/app
    state: directory                # touch | directory | link | absent
    owner: app
    group: app
    mode: '0750'                    # quoted, leading zero
    setype: httpd_sys_content_t

- ansible.builtin.copy:             # control node -> managed host
    src: files/app.conf             # or  content: "text\n"
    dest: /etc/app.conf
    mode: '0644'
    force: false                    # only if missing

- ansible.builtin.fetch:            # managed host -> control node
    src: /var/log/secure
    dest: backups                   # backups/HOST/var/log/secure

Edit and check

- ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?PermitRootLogin'    # replace the last match...
    line: PermitRootLogin no        # ...or append this line
    state: present

- ansible.builtin.blockinfile:
    path: /etc/hosts
    block: |
      172.25.250.10 servera
      172.25.250.11 serverb
    marker: "# {mark} LAB HOSTS"    # optional custom markers

- ansible.builtin.stat:
    path: /etc/motd
  register: motd

- ansible.builtin.debug:
    msg: "present"
  when: motd.stat.exists

Template task

- name: Deploy the configuration
  ansible.builtin.template:
    src: templates/app.conf.j2      # on the control node
    dest: /etc/app.conf             # on the managed host
    owner: root
    group: root
    mode: '0644'
    validate: /usr/sbin/app --check %s
  notify: restart app
# ansible.cfg
[defaults]
ansible_managed = Ansible managed

Jinja2

# {{ ansible_managed }}
{# a comment: not in the output #}
Listen {{ ansible_facts['default_ipv4']['address'] }}:{{ http_port }}

{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }} {{ host }}
{% endfor %}

{% for u in users if u != "root" %}
{{ loop.index }}: {{ u }}
{% endfor %}

{% if ansible_facts['memtotal_mb'] >= 2048 %}
workers 8
{% else %}
workers 2
{% endif %}

{{ settings | to_nice_yaml }}
{{ owner | default('nobody') }}
You want toModule
Copy a file, or write inline textansible.builtin.copy
Deploy a per-host fileansible.builtin.template
Attributes, directory, link, removeansible.builtin.file
One line in a fileansible.builtin.lineinfile
A block of lines in a fileansible.builtin.blockinfile
Bring a file backansible.builtin.fetch
Status or checksumansible.builtin.stat
Sync a directory tree (rsync)ansible.posix.synchronize
Which module is `copy` in reverse?
`ansible.builtin.fetch`: managed host → control node.
How should `mode` be written?
Quoted octal with the leading zero, `'0644'`, or symbolic, `u=rw,g=r,o=r`.
What does `state: absent` do on a directory?
Removes it and everything inside.
What does `force: false` mean for `copy`?
Copy only if the destination does not exist.
How does `blockinfile` find its block on the next run?
By the **BEGIN / END marker** comment lines (set with `marker`).
Where is the information in a registered `stat`?
Under `.stat`, for example `result.stat.exists` or `result.stat.checksum`.
Is `setype` from the file module permanent?
No. Like `chcon`; `restorecon` resets it. Use `sefcontext` or the selinux role to change the policy.
The three Jinja2 delimiters?
`{{ }}` output, `{% %}` statements, `{# #}` comments.
Where are templates rendered?
On the **control node**, once per host, with that host’s variables and facts.
Which variable counts loop passes in a template?
`loop.index` (from 1); `loop.index0` from 0.
Can a playbook use `{% for %}`?
No: Jinja2 control structures are for templates. Tasks use `loop` and `when`.
What does `validate` do in a template task?
Runs a check on the rendered file (`%s`) before replacing the real one.