updating PATH with ansible - system wide
I had a requirement today where I needed to install node.js from source in a custom location (/opt/node) on an ubuntu host. Compiling it from source on the _target hosts (though not the ideal way to go about things), wasn't a problem at all - and everything went smoothly. Unfortunately, turns out that the global npm packages installed from this custom location like to use #!/usr/bin/env node
as their shebangs - which essentially means - nothing will really work unless node is on the PATH
.
Fair enough. I figured I'll just add the PATH
extension to the ~/.bashrc
and ~/.bash_profile
of the deploy user (in my case - fireball
running as sudo) and that'll be that for the deployment (though it would suck for every other user on the system since they'd have to figure out their environments themselves). Unfortunately, that didn't got too well as that update to the environment didnt get picked up by fireball
nor did it show up when i did ssh root@${host} echo $PATH
.
Next up, I tried running the task that uses node with an environment:
directive ala:
- name: compile sources
shell: >
coffee -o lib -c src
chdir=${mysourcedir}
environment:
PATH:$PATH:/opt/node/bin
... which also didn't work as the command was run as PATH='$PATH:/opt/node/bin' coffee -o lib -c src
. This resulted in $PATH
not being evaluated at all and the command catastrophically failing.
After some googling, this post about System wide environment variables made enough sense and I went down the path of using lineinfile to update /etc/environment
. My requirements for updating the PATH=/usr/bin:/usr/local/bin.....
type line were:
- the new entry should only be added once
- the new entry should not destroy entries added by other tasks
- the entry should respect quoting (or the lack there-of) in the PATH value
The final task to update the PATH variable was thus:
- name: add {{extra_path}} to path
lineinfile: >
dest=/etc/environment
state=present
backrefs=yes
regexp='PATH=(["]*)((?!.*?{{extra_path}}).*?)(["]*)$'
line="PATH=\1\2:{{extra_path}}\3"
Written by Ali-Akber Saifee
Related protips
2 Responses
The only issue is that it won't work if the file is empty of there isn't line for the PATH already in it, in that case, it WON'T add the line.
I fixed it like this:
name: Checks if the environment file already has an entry for the PATH
replace:
dest=/etc/environment
regexp="PATH=(.*)"
replace="PATH=\1"
register: checkIfPATHIsHerename: Add a PATH entry with {{extrapath}} if the PATH is not already defined
lineinfile:
dest=/etc/environment
state=present
line="PATH={{extrapath}}"
regexp=''
insertafter=EOF
when: checkIfPATHIsHere.changed == falsename: add {{extrapath}} to the PATH
lineinfile:
dest=/etc/environment
state=present
backrefs=no
regexp="PATH=(["])((?!.?{{extrapath}}).?)(["])$"
line="PATH=\1\2:{{extra_path}}\3"
when: checkIfPATHIsHere.changed
I had to modify your task in order to make it compile.
- name: add {{ extra_path }} to path
ansible.builtin.lineinfile:
dest: /etc/environment
state: present
backrefs: yes
regexp: 'PATH=(["]*)((?!.*?{{ extra_path }}).*?)(["]*)$'
line: 'PATH=\1\2:{{ extra_path }}\3'
My ansible version:
ansible 2.9.21
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/dist-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.16 (default, Oct 10 2019, 22:02:15) [GCC 8.3.0]