How to use single template and copy it each time different - loops

I have a single template for mount units and want to copy this template multiple times, each time with different variables and a different filename (due to systemd mounts).
This is what my task looks so far
- name: copy mount unit files
become: yes
become_user: root
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
loop:
- { src: 'mounts/foo.mount.j2' , dest: '/etc/systemd/system/{{ mount_name }}.mount' }
This is my j2
Unit]
Description=MOUNT
Requires=systemd-networkd.service
After=network-online.target
Wants=network-online.target
[Mount]
Type=nfs4
What={{ what }}
Where={{ where }}
TimeoutSec=30
[Install]
WantedBy=multi-user.target
And this is my file for group_vars
what:
- files.foo.de:/server-test/www/vhost/test_customizing
- files.foo.de:/server-test/www/vhost/test_data
- files.foo.de:/server-test/www/vhost/plugins
where:
- /var/www/vhost/test_customizing
- /var/www/vhost/test_data
- /var/www/vhost/plugins
mount_name:
- var-www-vhost-test_customizing
- var-www-vhost-test_data
- var-www-vhost-plugins
What it does so far is to copy a single mount file with every translated variable in it.
What do have to add to make it work?
Thank you in advance, im really stuck here.

Related

Ansible: loop trough list of files of different users, sort by date, delete oldest x ones of each user

I am struggling with this issue since several days and would appreciate your help. I would like to check if the crontab file for several users exist on a host. If so, a backup shall be done and the oldest x backups shall be removed.
To achieve this I first check if the crontab exists:
- name: check if crontab exists
ansible.builtin.stat:
path: "/var/spool/cron/tabs/{{ item }}"
loop: "{{ users }}"
register: crontabFile
Then I perform a backup of the file:
- name: backup old crontab
ansible.builtin.copy:
src: "{{ item.stat.path }}"
dest: "{{ item.stat.path }}_{{ ansible_date_time.iso8601_basic_short }}"
mode: "preserve"
remote_src: true
loop: "{{ crontabFile.results }}"
when: item.stat.exists
This works fine so far. Afterwards I check for existing backups:
- name: find backups of crontab
ansible.builtin.find:
paths: "{{ item.stat.path | dirname }}"
patterns: "{{ item.stat.path | basename }}_*"
loop: "{{ crontabFile.results }}"
register: crontabBackup
when: item.stat.exists
The next step would be to loop over the results of crontabBackup and remove the oldest x files of the backups for each user individually.
The following does not work:
- name: delete oldest backups of crontab, keep last 5
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop: "{{ (crontabBackup.results|selectattr('files', 'defined')|map(attribute='files')|flatten|sort(attribute='mtime')|map(attribute='path')|list)[:-5] }}"
What happens is, that a flat list of all files is generated and the oldest files of this list get removed. What I want is to sort the list per user and remove the files per user.
After trying many different approaches, I think I've figured it out for myself. I will share my solution in case anyone is facing the same issue.
The solution is to use an outer loop that includes the inner loop via include_tasks as mentioned here.
# main.yml
- include_tasks: delete_backups_inner_loop.yml
loop: "{{ crontabBackup.results|selectattr('files', 'defined')|map(attribute='files') }}"
loop_control:
loop_var: userLoop
# delete_backups_inner_loop.yml
- name: delete oldest backups of crontab, keep last 5
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ (userLoop|sort(attribute='mtime'))[:-5] }}"

Ansible - Versionfile check

I want to be able to read a versionfile if it exists, and check its contents. Then return True if the version changed or the file does not exists, False if versionfile exists and the version matches the content.
Basically this:
# setup test data
- set_fact:
version_expected: "0001"
version_path: "/path/to/version"
version_owner: "root"
version_group: "root"
# this block is used to check for version changes
- name: check version change
block:
- name: check version file
stat:
path: "{{version_path}}"
register: version_file
- set_fact:
version_remote: "{{ lookup('file', version_path) | default('') }}"
when: version_file.stat.exists
- set_fact:
version_changed: not version_file.stat.exists or version_remote != version_expected
# test writing new version
- name: write file
copy:
dest: "{{version_path}}"
content: "{{version_expected}}"
owner: "{{version_owner}}"
group: "{{version_group}}"
when: version_changed
My problem is: This is somewhat ugly and becoming quite redundant in my roles.
Is there a more elegant way to do this?
Is there maybe a module for this? (though I found none)
Or should I just write a module for this?
Best regards,
2d4r
EDIT:
im only meaning the "check version change" block, the surrounding code is for debugging only.
To be more specific, I want to download a server binary, but only if my expectet version differs from the content of the versionfile.
I want to write the new version to file, if (and only if) the download was successfull, but that is not part of my question.
EDIT2:
I got this by now:
# roles/_helper/tasks/version_check.yml
- name: check if file exists
stat:
path: "{{version_path}}"
register: version_file
- name: get remote version
slurp:
src: "{{version_path}}"
register: version_changed
when: version_file.stat.exists
# (False if versionfile exists and version is expected; True else)
- name: set return value
set_fact:
version_changed: "{{ not version_file.stat.exists or ((version_changed.content | b64decode) is version_compare(version_expected, 'ne')) }}"
used like this:
# /roles/example/tasks/main.yml
- include_role:
name: _helper
tasks_from: version_check
vars:
version_path: "{{file_version_path}}"
version_expected: "{{file_version_expected}}"
- name: doing awesome things
when: version_changed
block:
- name: download server
[...]
- name: write version
copy:
dest: "{{file_version_path}}"
content: "{{file_version_expected}}"
It kills the redundancy, but is still not what I want.
Sadly I can not register a return value from a role.
Delete everything except for write file task and remove the condition.
Ansible does this automatically for you.
- name: write file
copy:
dest: "{{version_path}}"
content: "{{version_expected}}"
owner: "{{version_owner}}"
group: "{{version_group}}"
After you changed the question, given the information provided, the only thing I can point to is to use slurp module instead of lookup, as an lookup plugins work locally in the control machine.
Compare versions using your logic or built-in version_compare filter/test.

ansible to pick & iterate the location name from the file sequencly

I have written a playbook to install our custom collectd and that's working , where i'm changing the configuration with lineinfile module now i have another situation where i have multiple site names like one i have in my playbook ie richmod as follows:
Prefix "collectd.dns.NA.richmond.physical.
i have multiple site name viz richmond, carry, london, boston hence looking forward to put them into a varible and call that variable to assign the value.
lets suppose when it run the playbook on first Server it should pick up "richmon" for second it should pick up carry, for third it should london and so on.. looking for ideas..
---
- name: Playbook to Install CollectD
#hosts: all[1]
hosts: all
remote_user: root
become: true
tasks:
- name: Downloading collectd
get_url:
url="http://my-dc/collectd-5.7.2.tar.gz"
dest="/opt/"
- name: Extracting collectd archive
unarchive:
src="/opt/collectd-5.7.2.tar.gz"
dest="/opt/"
remote_src=True
- name: Creating soft link to collectd Dir
file:
src: "/opt/collectd-5.7.2"
dest: "/opt/collectd"
state: link
owner: root
group: root
#############################################################################################
# Dont Disable the gather_facts at all as {{ ansible_hostname }} absolutlty depends on facts #
# ###########################################################################################
- name: Committing changes to collectd configuration....
lineinfile:
dest: "{{ item.dest }}"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backrefs: yes
with_items:
- { dest: '/opt/collectd/etc/collectd.conf', regexp: '#Hostname "collectServer"', line: 'Hostname "{{ ansible_hostname }}"' }
- { dest: '/opt/collectd/etc/collectd.conf', regexp: '# Prefix "collectd.unix."', line: ' Prefix "collectd.dns.NA.richmond.physical."' }
- name: Copy the collectd Daemon to init ..
copy:
src: "/opt/collectd/startup/collectd"
dest: "/etc/init.d/"
remote_src: True
mode: 0755
owner: root
group: root
- name: starting collectd Service
service:
name: collectd
state: started
enabled: yes

Ansible: how do I avoid code repetitions with file src and with_first_found?

I have several dozen copy actions that do the same dance to find an appropriate file based on the following config file storage hierarchy (can't change it):
{{role_path}}/file.name.{hostname}
{{role_path}}/file.name
/config/current/file.name.{hostname}
/config/current/file.name
/config/legacy/file.name.{hostname}
/config/legacy/file.name
Is there a way to avoid repeating the whole with_first_found clause for every config file as in the following?
- name: Copy /etc/file.name
copy:
src: "{{item}}"
dest: "/etc/file.name"
owner: root
group: root
mode: 0644
with_first_found:
- files:
- files/etc/file.name.{{inventory_hostname}}
- files/etc/file.name
paths:
- "{{ role_path }}"
- /config/current
- /config/legacy
Extract the tasks to a separate file and loop over include using loop_control in outer loop to avoid conflict in item variable.

In Ansible, how can I fetch file from multiple nodes and store this in one file centralized?

All what I need is in title, for example I want to know how I can do somethings like that :
---
- hosts: ansible-clients
tasks:
- name: Fetch source list from clients
fetch: src=/etc/apt/sources.list
dest=/tmp/allnodes.sourcelist
OR in simply way
echo remote#/etc/apt/sources.list >> local#/tmp/allnodes.sourcelist
I can create and run script in local but the only condition I have is to do all actions in one playbook.
You can use this play:
---
- hosts: ansible-clients
tasks:
- name: Fetch source list from clients
fetch:
src: /etc/apt/sources.list
flat: yes
dest: "/tmp/{{ inventory_hostname }}.sourcelist"
- name: Merge files
run_once: yes
delegate_to: localhost
shell: "cat /tmp/{{ item }}.sourcelist >> /tmp/allnodes.sourcelist"
with_items: "{{ groups['ansible-clients'] }}"
First task is used to fetch all files from remotes and store them in /tmp. inventory_hostname is used in filename to be sure it is unique.
Second task is run once on any host, and append all files (get list of hosts linked to group ansible-clients) in final file

Resources