Sometimes some files are leftovers from previous Ansible playbook executions or were generated in between Ansible executions by the application.
In this case, it is hard to predict what final version of the config will be generated after running Ansible once again.
One possible case from the real world is the main config of nginx /etc/nginx/nginx.conf
that has a include *.conf
statement at the very end.
After installation, Nginx provides you with conf.d/default.conf
that will be included.
However, one may want to get rid of this file on production servers.
The first solution would be to explicitly remove this file:
- name: remove default.conf
file:
path: "/etc/nginx/conf.d/default.conf"
state: absent
notify: reload nginx
The problem is that none is sure that all pre-defined configs have been removed. As for today, this is enough, but tomorrow package maintainers may add other files that silently are added to your production system during installation.
The second solution would be to remove all files from /etc/nginx/conf.d
and then add only the necessary ones:
- name: remove all from conf.d
shell: "rm -rf /etc/nginx/conf.d/*.conf"
notify: reload nginx
- name: add required configs
copy:
src: "{{ item }}"
dest: "/etc/nginx/conf.d/{{ item }}"
with_items: "{{ nginx_configs }}"
notify: reload nginx
The problem here is that the event reload nginx
is triggered every time, regardless of the presence of real changes.
In other words, the playbook will not be idempotent anymore.
The third approach would be to remove all files that are not on the “white list”:
- name: get list of files from the directory
find:
paths: "/etc/nginx/conf.d"
file_type: file
hidden: true
register: _dir_files
- name: remove files that are not on the list
file:
path: "{{ item.path }}"
state: absent
when: "item.path | basename not in nginx_configs | default([])"
with_items: "{{ _dir_files.files | default([]) }}"
notify: reload nginx
- name: add required configs
copy:
src: "{{ item }}"
dest: "/etc/nginx/conf.d/{{ item }}"
with_items: "{{ nginx_configs }}"
notify: reload nginx
This returns idempotency back because it triggers the reload nginx
event only when real changes were made.
I do not consider this solution to be ideal but this snippet may be used.