Ansible: generating templates with deep directory structure using with_filetree

If you have a simple directory containing multiple template files that should be generated on a target host, the ‘with_fileglob‘ lookup plugin provides an easy way to render them.  Below is an example rendering all the files from the ‘templates’ directory of a role.

 - name: create file out of every file in template directory
   template:
     src: "{{item}}"
     dest: /tmp/.
   with_fileglob: "{{role_path}}/templates/*"

But ‘with_fileglob’ handles only flat directories and cannot handle the situation where there are subdirectories of templates that you would like to render.  This is where the ‘with_filetree‘ lookup plugin can assist.  This is included in the the ‘community.general‘ collection, so first ensure it is installed.

# install 'community.general' collection
ansible-galaxy collection install community.general
ansible-galaxy collection list

Assuming there is a set of nested subdirectories in the ‘templates’ directory of the role, first do the directory creation then follow that by template file generation.  This separation of directories versus files allows for better sensing of changes.

- set_fact:
    dest_dir: /tmp/filetreetest

- name: Create directory structure
  file:
    path: '{{dest_dir}}/{{ item.path }}'
    state: directory
    mode: '{{ item.mode }}'
  with_filetree: '{{role_path}}/templates/'
  loop_control:
    label: '{{item.path}}'
  when: item.state == 'directory'

- name: Generate Template files with directory structure
  template:
    src: '{{ item.src }}'
    dest: '{{dest_dir}}/{{ item.path }}'
    mode: '{{ item.mode }}'
  with_filetree: '{{role_path}}/templates/'
  loop_control:
    label: '{{item.path}}'
  when: item.state == 'file'

The ‘loop_control’ is not essential, but abbreviates the output for better readability of the Ansible output.

If you are using my example on github playbook-filetree.yaml, with the filetreetest role, this can be tested using the following invocation.

ansible-playbook playbook-filetree.yml --connection=local

REFERENCES

docs.ansible, fileglob_lookup

docs.ansible, filetree_lookup

ansible galaxy, community.general collection

stackoverflow, example using with_filetree

stackoverflow, another example using with_filetree

NOTES

‘with_filetree’ works fine, but if you want to be explicit about the namespace of the collection, use ‘with_community.general.filetree’