'Using ansible template module to iteratively apply template to all files within a template directory within a role

I am using ansible roles and templates are super useful. However, I am trying to write a play using roles (within tasks/main.yml) to template not a single file, but a set of files under a subdirectory of the template directory. Suppose I have a role directory structure like this:

-- tasks
   - main.yml
-- templates
   - file1.j2
   - file2.j2
   - dirA
      - file3.j2
      - file4.j2
      - dirB
        - file5.j2
        - file6.j2
   - dirC
      - file7.j2
      - file8.j2

Given a location (called destinationDir) on the target, I want to create

 - destinationDir
   - file1
   - file2
   - dirA
      - file3
      - file4
      - dirB
        - file5
        - file6
   - dirC
      - file7
      - file8

However, I don't want to create a list of files and change the play every time I add a new file to the structure. Is there a way of dynamically figuring out all of the .j2 files under the template directory and having the template module called for each placing them (with the directory structure still in tact) in the target directory? I want to be able to just drop in new files into the role template directory and run the play to automatically replicate all the items. I have seen with_filetree, but I haven't been able to figure out how to get it to look in the 'templates' directory of the role it is running.



Solution 1:[1]

Given the tree

shell> tree templates/
templates/
??? dirA
?   ??? dirB
?   ?   ??? file5.j2
?   ?   ??? file6.j2
?   ??? file3.j2
?   ??? file4.j2
??? dirC
?   ??? file7.j2
?   ??? file8.j2
??? file1.j2
??? file2.j2

and the variable dest_dir

dest_dir: destinationDir

Find and create the directories first

    - find:
        path: templates
        file_type: directory
        recurse: true
      register: result
    - file:
        state: directory
        path: "{{ dest_dir }}/{{ _path }}"
      loop: "{{ result.files|map(attribute='path')|list }}"
      vars:
        _path: "{{ item.split('/', 1)|last }}"

gives

shell> tree destinationDir/
destinationDir/
??? dirA
?   ??? dirB
??? dirC

Now find and template the files

    - find:
        path: templates
        recurse: true
      register: result
    - template:
        src: "{{ _src }}"
        dest: "{{ dest_dir }}/{{ _dest }}"
      loop: "{{ result.files|map(attribute='path')|list }}"
      vars:
        _src: "{{ item.split('/', 1)|last }}"
        _dest: "{{ _src|splitext|first }}"

gives

shell> tree destinationDir/
destinationDir/
??? dirA
?   ??? dirB
?   ?   ??? file5
?   ?   ??? file6
?   ??? file3
?   ??? file4
??? dirC
?   ??? file7
?   ??? file8
??? file1
??? file2

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vladimir Botka