4

I want to download some binaries like Helm and make them globally available using $PATH. To avoid downloading with root privileges or alternatively have two steps (download with standard user and move to some folder in $PATH like /usr/local/bin), my idea was to create $HOME/bin and add it to $PATH.

This blog article was used to add a custom path to /etc/environment. Then I reload it as described here. This is my POC playbook where I try to add exa:

- name: Test
  hosts: all

  vars:
    - bin: /home/vagrant/bin

  tasks:
  - name: Test task
    file:
      path: "{{bin}}"
      state: directory

  - name: Add {{bin}} to path
    become: yes
    lineinfile: >
        dest=/etc/environment
        state=present
        backrefs=yes
        regexp='PATH=(["]*)((?!.*?{{bin}}).*?)(["]*)$'
        line="PATH=\1\2:{{bin}}\3"

  - name: Check path1
    shell: echo $PATH

  - name: Download exa
    unarchive:
      src: https://github.com/ogham/exa/releases/download/v0.8.0/exa-linux-x86_64-0.8.0.zip
      dest: "{{bin}}"
      remote_src: yes

  - name: reload env file
    shell: for env in $( cat /etc/environment ); do export $(echo $env | sed -e 's/"//g'); done

  - name: Check path after reload env file
    shell: echo $PATH

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version

In the last task Test exa from PATH it throws the error:

"stderr": "/bin/sh: 1: exa-linux-x86_64: not found"

The echo $PATH commands remain both at

"stdout": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

But the modified /etc/environment works. When I go to SSH on the machine without Ansible, $PATH is fine and also exa-linux-x86_64 --version works:

~$ echo $PATH
/home/vagrant/bin:/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/vagrant/bin:/snap/bin

Environment

Ubuntu 18.04 host system running Vagrant with a Ubuntu 16.04 box. Ansible was executed by Vagrant on Ubuntu 16.04.

Possible workarounds

Using separate env variable

When setting the environment variable like this

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version
    environment:
      PATH: "{{ ansible_env.PATH }}:{{bin}}"

it works. But I have to apply those lines at least on play-level. I would like to set it globally like /etc/environment does at regular shells. This questions seems to have the same target, but on Solaris. The answer seems to only set $PATH from the host, which isn't useful for me since the custom bin dir isn't there.

Use only absolute paths

  - name: Test exa from PATH
    shell: "{{bin}}/exa-linux-x86_64 --version"

This causes less overhead, but you've to remember prefixing your commands always with the path variable. Seems also error-prone

Understanding the problem

I want a real solution and realize what's causing the problem. It's not clear for me why $PATH modification is so hard on Ansible, where it can be done quite easily in the underlying Linux system. This question says we don't have an interactive session in Ansible. There seems to be no $PATH available. According to the documentation, we can archive this by passing -l to bash. So I found the following working:

  - name: Test exa from PATH
    shell: bash -l -c "exa-linux-x86_64 --version"

But the following results in an error:

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version
    args:
      executable: /bin/bash -l

Here Ansible breaks the command with wrong quoting of the args:

"'/bin/bash -l' -c 'exa-linux-x86_64 --version'"

This ticket recommends the Ansible team to fix this, so that we get an login shell with $PATH. Since 2014, no real solution was provided at all.

Questions

  1. What is the purpose of different shell types that get access to the modified $PATH or not?
  2. Why does Ansible complicate things? Wouldn't it be easier to provide a login shell that solves this issue? Are there reasons why they did what they did?
  3. How can we deal with the resulting problems? What is best practice?
tripleee
  • 175,061
  • 34
  • 275
  • 318
Lion
  • 16,606
  • 23
  • 86
  • 148
  • It is debatable whether Ansible is part of development. Admins and developers are becoming increasingly merged. Especially in the context that this question is asked to build a Kubernetes cluster which itself should act as development platform. But I don't think that this justifys the downvotes I got, since the question itself is a valid question - Independent if he's at SO or got moved to other platforms like DevOps (where it could be moved). – Lion Mar 17 '19 at 11:08
  • @VladimirBotka I'd go a step further: writing an Ansible configuration *is* software development, just not using a general-purpose programming language. – chepner Aug 04 '21 at 18:09

2 Answers2

0

To answer your questions

1) What is the purpose of different shell types that get access to the modified $PATH or not?

It's not worth the effort to unify it in all operating systems supported by Ansible. This also explains "It's not clear for me why $PATH modification is so hard on Ansible, where it can be done quite easy in the underlaying linux system."

2) Why Ansible complicates things? Wouldn't it be easier to provide a login shell that solve this issue? Are there reasons why they did what they did?

On the contrary, it's easier not to care about it. Keep it simple stupid is the reason.

3) How can we deal with the resulting problems? What is best practice?

Best practice over decades have been Tools, no policy

Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
0

Your attempt to "reload the environment" is wrong. You are running a subshell which modifies its own environment, but it obviously cannot modify its parent's environment.

A proper test would look something like

  - name: check path with modified env file
    shell: . /etc/environment; echo "$PATH"

PATH will already have been export:ed so there is no need to do that again. If you really wanted to, you could separately export PATH after . /etc/environment; but if the variable should be exported, then /etc/environment should take care of that, too. Perhaps see also Defining a variable with or without export

tripleee
  • 175,061
  • 34
  • 275
  • 318