Last Updated: September 30, 2021
·
77.31K
· alisaifee

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"

2 Responses
Add your response

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: checkIfPATHIsHere

  • name: Add a PATH entry with {{extrapath}} if the PATH is not already defined
    lineinfile:
    dest=/etc/environment
    state=present
    line="PATH={{extra
    path}}"
    regexp=''
    insertafter=EOF
    when: checkIfPATHIsHere.changed == false

  • name: add {{extrapath}} to the PATH
    lineinfile:
    dest=/etc/environment
    state=present
    backrefs=no
    regexp="PATH=(["])((?!.?{{extra
    path}}).?)(["])$"
    line="PATH=\1\2:{{extra_path}}\3"
    when: checkIfPATHIsHere.changed

over 1 year ago ·

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]

over 1 year ago ·