I'm trying to update a file with lineinfile in a loop, and it makes two backup file at once. Is there a way to not make the second one?
- name: disable kernelhints on apt install
lineinfile:
path: /etc/needrestart/needrestart.conf
regexp: '^.*\$nrconf{{"{"}}{{ item }}{{"}"}}.*$'
line: '$nrconf{{"{"}}{{ item }}{{"}"}} = 0;'
backup: true
loop:
- 'kernelhints'
- 'ucodehints'
CodePudding user response:
You can track the loop index and calculate a boolean for backup
Note that this solution is far from perfect as you won't get any backup if the first iteration did not change anything or failed.
- name: Disable kernelhints on apt install
ansible.builtin.lineinfile:
path: /etc/needrestart/needrestart.conf
regexp: '^.*\$nrconf{{"{"}}{{ item }}{{"}"}}.*$'
line: '$nrconf{{"{"}}{{ item }}{{"}"}} = 0;'
backup: "{{ it | int == 0 }}"
loop:
- 'kernelhints'
- 'ucodehints'
loop_control:
index_var: it
CodePudding user response:
As a workaround, you can 'preen' your backup files. For example, create a list of your files
my_backups:
- /tmp/test.conf
Find all backups and delete all but the first one
- name: Find my backups
find:
paths: "{{ item|dirname }}"
patterns: "{{ item|basename }}.*~"
register: out
loop: "{{ my_backups }}"
- name: Keep the first backup only
file:
state: "{{ ansible_loop.last|ternary('file', 'absent') }}"
path: "{{ item.1.path }}"
with_subelements:
- "{{ out.results }}"
- files
loop_control:
label: "{{ item.1.path }}"
extended: true
Notes
- Example of a complete playbook for testing
- hosts: localhost
gather_facts: false
vars:
my_backups:
- /tmp/test.conf
tasks:
- lineinfile:
path: /tmp/test.conf
line: "{{ item }}"
backup: true
loop:
- line2
- line3
- name: Find my backups
find:
paths: "{{ item|dirname }}"
patterns: "{{ item|basename }}.*~"
register: out
loop: "{{ my_backups }}"
- name: Keep the first backup only
file:
state: "{{ ansible_loop.last|ternary('file', 'absent') }}"
path: "{{ item.1.path }}"
with_subelements:
- "{{ out.results }}"
- files
loop_control:
label: "{{ item.1.path }}"
extended: true
- Example of the playbook's output
PLAY [localhost] *****************************************************************************
TASK [lineinfile] ****************************************************************************
changed: [localhost] => (item=line2)
changed: [localhost] => (item=line3)
TASK [Find my backups] ***********************************************************************
ok: [localhost] => (item=/tmp/test.conf)
TASK [Keep the first backup only] ************************************************************
changed: [localhost] => (item=/tmp/test.conf.174273.2022-12-14@08:08:01~)
changed: [localhost] => (item=/tmp/test.conf.179001.2022-12-14@08:38:36~)
changed: [localhost] => (item=/tmp/test.conf.178970.2022-12-14@08:38:36~)
ok: [localhost] => (item=/tmp/test.conf.174242.2022-12-14@08:08:01~)
PLAY RECAP ***********************************************************************************
localhost: ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- The result will be
shell> cat /tmp/test.conf
line1
line2
line3
- Only the first backup will be present
shell> cat /tmp/test.conf.174242.2022-12-14@08\:08\:01~
line1
- The loop_control doesn't work properly in controlling the backup. For example, given the file
shell> cat /tmp/test.conf
line1
The task below
- lineinfile:
path: /tmp/test.conf
line: "{{ item }}"
backup: "{{ ansible_loop.index == 1 }}"
loop:
- line2
- line3
loop_control:
extended: true
works as expected
TASK [lineinfile] ****************************************************************************
changed: [localhost] => (item=line2)
changed: [localhost] => (item=line3)
, creates the file
shell> cat /tmp/test.conf
line1
line2
line3
, and also creates the backup on the first iteration
shell> cat /tmp/test.conf.170212.2022-12-14@07\:09\:41~
line1
But when you are given the file
shell> cat /tmp/test.conf
line1
line2
the task also creates the file as expected
TASK [lineinfile] ****************************************************************************
ok: [localhost] => (item=line2)
changed: [localhost] => (item=line3)
shell> cat /tmp/test.conf
line1
line2
line3
but no backup is created because the first iteration changes nothing.