Reputation: 305
So I'm trying to adding value from user's input to properties.yaml using insertafter lineinfile
this is what my code looks like:
- name: Update file
lineinfile:
path: "~/test/properties.yaml"
insertafter: "this_line:"
line: 'test123'
mode: 0644
become: yes
This is what my properties.yaml looks like:
this_line:
another_line:
- 'test1'
- 'test2'
- 'test3'
that_line:
another_line:
- 'test1'
- 'test2'
- 'test3'
When I tried run it for the first time, it worked, and my properties.yaml change to this:
this_line:
test123
another_line:
- 'test1'
- 'test2'
- 'test3'
that_line:
another_line:
- 'test1'
- 'test2'
- 'test3'
However, After trying to run it the second time to add line after that_line , it won't work. I was expecting something like this:
this_line:
test123
another_line:
- 'test1'
- 'test2'
- 'test3'
that_line:
test123
another_line:
- 'test1'
- 'test2'
- 'test3'
I also tried this code:
- name: Update file
lineinfile:
path: "~/test/properties.yaml"
insertafter: "that_line:"
line: 'test12345'
mode: 0644
become: yes
And it does change to this:
this_line:
test123
another_line:
- 'test1'
- 'test2'
- 'test3'
that_line:
test12345
another_line:
- 'test1'
- 'test2'
- 'test3'
So sometimes it works and the other it didn't. Is there something I'm missing from the use of insertafter? Thankyou.
Upvotes: 1
Views: 1082
Reputation: 68254
Short answer: There will be no changes if the line is present in the file.
Details: The module lineinfile quote: "ensures a particular line is in a file ... when you want to change a single line in a file only." For example, given the simplified file
shell> cat /tmp/test/properties.yaml
test123
this_line
that_line
The playbook
shell> cat pb.yml
- hosts: localhost
tasks:
- lineinfile:
path: /tmp/test/properties.yaml
line: test123
- lineinfile:
path: /tmp/test/properties.yaml
insertafter: that_line
line: test123
- lineinfile:
path: /tmp/test/properties.yaml
insertafter: this_line
line: test123
doesn't change anything if the line is present anywhere in the file
shell> ansible-playbook pb.yml
PLAY [localhost] *****************************************************************************
TASK [lineinfile] ****************************************************************************
ok: [localhost]
TASK [lineinfile] ****************************************************************************
ok: [localhost]
TASK [lineinfile] ****************************************************************************
ok: [localhost]
PLAY RECAP ***********************************************************************************
localhost: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Solution: You can use the module blockinfile if you want to insert multiple line(s) that already exist in a file. For example, let's say you want insert line
test123
after the line this_line
in the file
shell> cat /tmp/test/properties.yaml
test123
this_line
that_line
You'll have to mark the block first. Download mark_block.yml
shell> cat tasks/mark-block.yml
---
- name: "mark-block: Check begin marker {{ item.1.marker }}"
ansible.builtin.command:
cmd: >
grep -q '# BEGIN ANSIBLE MANAGED BLOCK {{ item.1.marker }}' {{ item.0.path }}
register: checkmarker
ignore_errors: true
changed_when: false
- block:
- name: "mark-block: Create begin marker {{ item.1.marker }}"
ansible.builtin.replace:
path: '{{ item.0.path }}'
regexp: '{{ item.1.regex1 }}'
replace: |-
{{ '#' }} BEGIN ANSIBLE MANAGED BLOCK {{ item.1.marker }}
{{ item.1.replace1 }}
- name: "mark-block: Create end marker {{ item.1.marker }}"
ansible.builtin.replace:
path: '{{ item.0.path }}'
regexp: '({{ item.1.regex1 }}[\s\S]*?){{ item.1.regex2 }}'
replace: |-
\g<1>
{{ item.1.replace2 }}
{{ '#' }} END ANSIBLE MANAGED BLOCK {{ item.1.marker }}
when:
- not ansible_check_mode
- checkmarker.rc != 0
# EOF
...
Declare the variable cl_files. The regex/replace pairs are trivial because the first and last lines of the block are the same
cl_files:
- path: /tmp/test/properties.yaml
markers:
- marker: 'this_line'
regex1: 'this_line'
replace1: 'this_line'
regex2: 'this_line'
replace2: 'this_line'
Mark the block
- name: "Mark block {{ item.1.marker }}"
ansible.builtin.include_tasks: tasks/mark-block.yml
with_subelements:
- "{{ cl_files }}"
- markers
loop_control:
label: "{{ item.0.path }}"
gives
shell> cat /tmp/test/properties.yaml
test123
# BEGIN ANSIBLE MANAGED BLOCK this_line
this_line
# END ANSIBLE MANAGED BLOCK this_line
that_line
Now you can use the marker and update the block
- blockinfile:
path: /tmp/test/properties.yaml
marker: "# {mark} ANSIBLE MANAGED BLOCK this_line"
block: |-
this_line
test123
gives
shell> cat /tmp/test/properties.yaml
test123
# BEGIN ANSIBLE MANAGED BLOCK this_line
this_line
test123
# END ANSIBLE MANAGED BLOCK this_line
that_line
Example of a complete playbook for testing
- hosts: localhost
vars:
cl_files:
- path: /tmp/test/properties.yaml
markers:
- marker: 'this_line'
regex1: 'this_line'
replace1: 'this_line'
regex2: 'this_line'
replace2: 'this_line'
tasks:
- name: "Mark block {{ item.1.marker }}"
ansible.builtin.include_tasks: tasks/mark-block.yml
with_subelements:
- "{{ cl_files }}"
- markers
loop_control:
label: "{{ item.0.path }}"
- blockinfile:
path: /tmp/test/properties.yaml
marker: "# {mark} ANSIBLE MANAGED BLOCK this_line"
block: |-
this_line
test123
See the Ansible role config_light. Review the documentation.
Upvotes: 1