I need to place a line of text onto the last line of a file using Ansible. If the line already exists in the file, I need to move it to the last line of the file. If the line already exists as the last line in the file, I don't need to do anything.
I currently have this block of Ansible code, which simply adds the correct line to the end of the correct file:
- name: Add LD_LIBRARY_PATH fix to end of .bash_profile (libcurl fix)
ansible.builtin.lineinfile:
path: "{{ agent_home_dir }}.bash_profile"
line: export LD_LIBRARY_PATH="/usr/lib64:$LD_LIBRARY_PATH"
insertafter: EOF
create: yes
tags:
- libcurl
The reason this Ansible block is not sufficient is because, after this Ansible block executes, it is possible that a software installation on the host will re-define the variable in the same file on a later line. This un-does the fix that the Ansible block is executing (because the variable is overwritten). When the Ansible code runs again, rather than fixing the issue by moving the line to the end of the file, it simply sees that the line exists in the file and therefore doesn't do anything.
I could have one Ansible block that deletes the line followed by one Ansible block that re-adds the line to the end of the file. This would verify with certainty that the line is always at the end of the file. However, this would cause a change on the host every pass-through of Ansible, which is not ideal. Code example below.
- name: Remove LD_LIBRARY_PATH fix from .bash_profile (libcurl fix)
ansible.builtin.lineinfile:
path: "{{ agent_home_dir }}.bash_profile"
state: absent
regexp: '^export LD_LIBRARY_PATH="/usr/lib64:$LD_LIBRARY_PATH"'
tags:
- libcurl
- name: Add LD_LIBRARY_PATH fix to end of .bash_profile (libcurl fix)
ansible.builtin.lineinfile:
path: "{{ agent_home_dir }}.bash_profile"
line: export LD_LIBRARY_PATH="/usr/lib64:$LD_LIBRARY_PATH"
insertafter: EOF
create: yes
tags:
- libcurl
Is it possible to accomplish what I am attempting to accomplish (verify the last line of the file is correct on each Ansible pass-through, and correct it if it needs correction) without unnecessarily editing the file on every pass-through?
This is the solution I ended up going with:
- name: Check for LD_LIBRARY_PATH fix (libcurl fix)
ansible.builtin.shell:
cmd: echo $(tail -n 1 .bash_profile)
chdir: '{{ controlm_home_dir }}'
register: bash_profile_last_line
- block:
- name: Remove LD_LIBRARY_PATH fix from .bash_profile (libcurl fix)
ansible.builtin.lineinfile:
path: '{{ controlm_home_dir }}.bash_profile'
regexp: '^export LD_LIBRARY_PATH='
state: absent
tags:
- libcurl
- name: Add LD_LIBRARY_PATH fix to end of .bash_profile (libcurl fix)
ansible.builtin.lineinfile:
path: '{{ controlm_home_dir }}.bash_profile'
line: export LD_LIBRARY_PATH="/usr/lib64:$LD_LIBRARY_PATH"
insertafter: EOF
create: yes
tags:
- libcurl
when: "'/usr/lib64:$LD_LIBRARY_PATH' not in bash_profile_last_line.stdout"
I effectively used the second solution mentioned in my original question, but preceded it with a block that checks to see if the fix is already in place using ansible.builtin.shell. I thought of this idea after looking at larsks's answer to my question. I didn't use larsks's full solution because I prefer to avoid using scripts in favor of Ansible modules. This solution works and accomplishes everything I originally wanted.