Can the templates module handle multiple templates / directories? - ansible

I believe the Ansible copy module can take a whole bunch of "files" and copy them in one hit. This I believe can be achieved by copying a directory recursively.
Can the Ansible template module take a whole bunch of "templates" and deploy them in one hit? Is there such a thing as deploying a folder of templates and applying them recursively?

The template module itself runs the action on a single file, but you can use with_filetree to loop recursively over a specified path:
- name: Ensure directory structure exists
ansible.builtin.file:
path: '{{ templates_destination }}/{{ item.path }}'
state: directory
with_community.general.filetree: '{{ templates_source }}'
when: item.state == 'directory'
- name: Ensure files are populated from templates
ansible.builtin.template:
src: '{{ item.src }}'
dest: '{{ templates_destination }}/{{ item.path }}'
with_community.general.filetree: '{{ templates_source }}'
when: item.state == 'file'
And for templates in a single directory you can use with_fileglob.

This answer provides a working example of the approach laid down by #techraf
with_fileglob expects only files to live within the templates folder - see https://serverfault.com/questions/578544/deploying-a-folder-of-template-files-using-ansible
with_fileglob will only parse files in the templates folder
with_filetree maintains the directory structure when moving the template files to dest. It auto creates those directories for you at dest.
with_filetree will parse all files in the templates folder and nested directories
- name: Approve certs server directories
file:
state: directory
dest: '~/{{ item.path }}'
with_filetree: '../templates'
when: item.state == 'directory'
- name: Approve certs server files
template:
src: '{{ item.src }}'
dest: '~/{{ item.path }}'
with_filetree: '../templates'
when: item.state == 'file'
Essentially, think of this approach as copying and pasting a directory and all its contents from A to B and whilst doing so, parsing all templates.

I could not manage to do it with the other answers. This is what worked for me:
- name: Template all the templates and place them in the corresponding path
template:
src: "{{ item.src }}"
dest: "{{ destination_path }}/{{ item.path | regex_replace('\\.j2$', '') }}"
force: yes
with_filetree: '{{ role_path }}/templates'
when: item.state == 'file'

In my case folder contain both files and jinja2 templates.
- name: copy all directories recursively
file: dest={{templates_dest_path}}/{{ item|replace(templates_src_path+'/', '') }} state=directory
with_items: "{{ lookup('pipe', 'find '+ templates_src_path +'/ -type d').split('\n') }}"
- name: copy all files recursively
copy: src={{ item }} dest={{templates_dest_path}}/{{ item|replace(templates_src_path+'/', '') }}
with_items: "{{ lookup('pipe', 'find '+ templates_src_path +'/ -type f -not -name *.j2 ').split('\n') }}"
- name: copy templates files recursively
template: src={{ item }} dest={{templates_dest_path}}/{{ item|replace(templates_src_path+'/', '')|replace('.j2', '') }}
with_items: "{{ lookup('pipe', 'find '+ templates_src_path +'/*.j2 -type f').split('\n') }}"

I did it and it worked. \o/
- name: "Create file template"
template:
src: "{{ item.src }}"
dest: "{{ your_dir_remoto }}/{{ item.dest }}"
loop:
- { src: '../templates/file1.yaml.j2', dest: 'file1.yaml' }
- { src: '../templates/file2.yaml.j2', dest: 'file2.yaml' }

Related

Ansible Could not find or access

I'm trying to make loop with 2 lookup(fileglob) in my task
---
- hosts: localhost
become: yes
become_user: root
tasks:
- name: Loop with 2 lookup
copy:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
loop:
- { src: "{{ lookup('fileglob', 'custom_scripts/*', wantlist=True) }}", dest: /var/custom_scripts/ }
- { src: "{{ lookup('fileglob','certs/*', wantlist=True) }}", dest: /var/custom_certs/ }
When i try to run this i get Could not find or access "path to files" in error log ansible is seeing all this files, because is listing all files which can't access. Permissions for all folders and files are set on 777
This logic to copy files seems to be flawed, and most likely causing this issue. item.src as you are trying to access, is a list (wantlist=True). In effect, you are passing a list of files to the src parameter of copy, and not 1 file.
Also, the copy module supports copying entire directories. So there should be no need to actually get the list of files.
A task such as below should do it:
- name: Loop with 2 lookup
copy:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
loop:
- { src: 'custom_scripts/', dest: '/var/custom_scripts' }
- { src: 'certs/', dest: '/var/custom_certs' }

Ansible delete Files with wildcard/regex/glob with exception

I want to delete files based on a wildcard but also add exceptions to the rule.
- hosts: all
tasks:
- name: Ansible delete file wildcard
find:
paths: /etc/wild_card/example
patterns: "*.txt"
use_regex: true
register: wildcard_files_to_delete
- name: Ansible remove file wildcard
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ wildcard_files_to_delete.files }}"
For example I want to except a file named "important.txt". How can I do that?
Just add a when condition to the task that deletes files. E.g., something like:
- name: Ansible remove file wildcard
file:
path: "{{ item.path }}"
state: absent
when: item.path != '/etc/wild_card/example/important.txt'
with_items: "{{ wildcard_files_to_delete.files }}"
This will skip a specific file. If you have a list of files to skip you could do this instead:
- name: Ansible remove file wildcard
file:
path: "{{ item.path }}"
state: absent
when: item.path not in files_to_skip
with_items: "{{ wildcard_files_to_delete.files }}"
vars:
files_to_skip:
- /etc/wild_card/example/important.txt
- /etc/wild_card/example/saveme.txt
And if you want to preserve files based on some sort of pattern, you could make use of ansible's match or search tests:
- name: Ansible remove file wildcard
file:
path: "{{ item.path }}"
state: absent
when: item.path is not search('important.txt')
with_items: "{{ wildcard_files_to_delete.files }}"

What is the ansible equivalent to find -exec cp with file extensions filtered?

I need to replace this kind of command:
- name: Copy files .par
shell: find {{ path_src }}/* -name '*.ext' -exec cp {} {{ path_dest }} \; | find {{ path_src }}/ -type f -a ! -name "*.*" -exec cp {} {{ part_dest }} \;
ignore_errors: yes
The '.ext' can be different on the same task and it's linked to the destination if i find '.sql' i want it to go to the destination .sql
I try this kind of solution
- name: TEST COPY
hosts: localhost
tasks:
- name: Test Find
find:
paths: /home/me/test/find_cpy
file_type: file
recurse: yes
patterns: ['*.ext','*.sql','*.sh']
register: find_list
- name:
debug: var=find_list
- name: test set fact
set_fact:
path_file: "{{ find_list.files | map(attribute='path') | list }}"
register: test_fact
- debug: var=test_fact
- name: test sql copy
copy:
src: "{{ test_fact.path}}"
dest: "/home/me/test/test_copy/sql"
owner: me
mode: 0755
when: ????
- name: test register
copy:
src: "{{ item.path }}"
dest: "/home/me/test/test_copy/"
owner: me
mode: 0755
with_items: "{{ find_list.files }}"
The test register is ok but the test sql copy i have no idea.
Any Ideas
Thanks
Only few changes are needed
- name: TEST COPY
hosts: localhost
gather_facts: false
tasks:
- name: Test Find
find:
paths: /home/me/test/find_cpy
file_type: file
recurse: yes
patterns: ['*.ext','*.sql','*.sh']
register: find_list
- name:
debug: var=find_list
- name: test set fact
set_fact:
path_file: "{{ find_list.files | map(attribute='path') | list }}"
# register: test_fact
Registered variable test_fact is not needed. The list of the paths has been stored in path_file.
- debug: var=path_file
- name: test sql copy
copy:
# src: "{{ test_fact.path}}"
src: "{{ item }}"
dest: "/home/me/test/test_copy/sql"
owner: me
mode: 0755
loop: "{{ path_file }}"
Loop the list of paths path_file and copy items to the destination.
- name: test register
copy:
# src: "{{ item.path }}"
src: "{{ item }}"
dest: "/home/me/test/test_copy/"
owner: me
mode: 0755
# with_items: "{{ find_list.files }}"
loop: "{{ path_file }}"
Loop find_list.files and item.path gives the same results as path_file and item. I'm not sure what the purpose of this task should be.

Ansible: Archive module does not take into account exclude_path param

I want to archive the following directory:
temp_build_directory: /tmp/mdr-upgrade
Where
$ ls -1 /tmp/mdr-upgrade
ansible
atr
composefiles
data
images
packs
wheelhouse
and the task is:
- name: archive_artifacts.yml --> Archive artifacts
archive:
path: "{{ temp_build_directory }}/*"
dest: "{{ target_tmp_dir }}/{{ artifacts_file_name }}"
exclude_path: "{{ target_tmp_dir }}/{{ ansible_dir }}"
And ansible_dir: ansible
Tarball ends up always containing the ansible folder.
Why is that?
edit: I am using target_tmp_dir: "/tmp"
exclude_path needs an absolute path (see docs).
Try again with:
- name: archive_artifacts.yml --> Archive artifacts
archive:
path: "{{ temp_build_directory }}/*"
dest: "{{ target_tmp_dir }}/{{ artifacts_file_name }}"
exclude_path: "{{ temp_build_directory }}/{{ ansible_dir }}"

Pass get_url downloaded zip files as variable to unarchive

I've just started to use Ansible to automate binary deployments.
When downloading the zip files and trying to unzip it by passing the downloaded zip files as variable to be unzipped/unarchived but an error is always thrown.
Snippet of the YML below:
- name: Download binaries
get_url:
url={{ download_server }}
url_username={{ username }}
url_password={{ passwd }}
dest={{ base_dir }}
register: bin_files
- set_fact:
my_unzipped_file: "{{ bin_files[0].stdout }}"
- name: UNZIPPING the files
unarchive: src={{ base_dir }}/{{ item }} dest={{ base_dir }} copy=no
with_items: my_unzipped_file
If it wasn't a user/pass protected URL you could erase the 'get_url' module and place the URL in the src: of Unarchive module.
Check the examples:
http://docs.ansible.com/ansible/latest/modules/unarchive_module.html
another way is to download all your files into a directory {{ bin_dir }} for example and use within the unarchive module 'with_fileglob' to unzip all .zip/.tar.gz and such
Example:
- name: UNZIPPING the files
unarchive:
src: "{{ item }}"
dest: "{{ base_dir }}/"
copy: no
with_fileglob:
- "{{ base_dir }}/*.zip"
- "{{ base_dir }}/*.tar.gz"
another tip for you IMHO you should drop the '=' code style in modules and move to ':' as you can see above, it's more human-readable
You corrected SNIPPET:
- name: Download binaries
get_url:
url: {{ download_server }}
url_username: {{ username }}
url_passwor: {{ passwd }}
dest: {{ base_dir }}
register: bin_files
- name: UNZIPPING the files
unarchive:
src: {{ base_dir }}/{{ item }}
dest: {{ base_dir }}
copy: no
with_items:
- "{{ bin_files.stdout }}"

Resources