$PATH in Ansible verändern

$PATH in Ansible verändern

Möchte man Anwendungen (Binaries) oder Skripte global aus jedem Verzeichnis heraus aufrufen können, gibt es grundsätzlich zwei Möglichkeiten:

  1. Ablegen in einem Ordner, der in $PATH bereits hinterlegt ist. Hier gibt es verschiedene Möglichkeiten. /usr/local/bin ist explizit für Programme ausgelegt, die nicht über die Paketverwaltung installiert wurden.
  2. Man erstellt einen eigenen Ordner, der wiederum an die $PATH Variable angehängt wird.

#1 ist der bevorzugte Weg, wenn die Anwendung systemweit genutzt werden soll und root-Rechte zur Verfügung stehen. Im folgenden Artikel möchten wir uns Szenario 2 anschauen. Händisch würde man die mit einer Zeile wie

export PATH="$PATH:/home/vagrant/bin"

in der .bashrc lösen und anschließend die Datei mit source neu laden. Oder alternativ /etc/environment, falls der Pfad global verfügbar sein soll. In Ansible gestaltet sich dies etwas komplexer.

$PATH für manuelle Nutzung anpassen

Soll $PATH für nachfolgende Anwendungen oder Nutzer verändert werden, kann man den Pfad einfach in der jeweiligen Datei (z.B. /etc/environment) ersetzen. Hier verwenden wir dafür die Ansible-Variable „bin“, die entsprechend gesetzt sein muss:

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

Veränderten $PATH in Ansible nutzen

Wenn wir uns danach per SSH auf der Maschine einloggen, sehen wir /home/vagrant/bin in der Ausgabe von echo $PATH. Doch in Ansible findet dies leider keine Anwendung für die darauffolgenden Befehle, wie folgendes Beispiel zeigt:

  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 path
    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: Test exa from PATH
    shell: exa-linux-x86_64 --version

Das zu erwartende Ergebnis wäre: Die Binary „exa“ wird heruntergeladen, in /home/vagrant/bin entpackt und zeigt uns am Schluss die Version 0.8.0 an, da der Pfad zuvor global in $PATH hinterlegt wurde. Stattdessen ist eine Fehlermeldung zu sehen:

fatal: [default]: FAILED! => {"changed": false, "cmd": "'/bin/bash -l' -c 'exa-linux-x86_64 --version'", "msg": "[Errno 2] No such file or directory", "rc": 2}

Lässt man sich $PATH ausgeben, fehlt der Ordner. Dies liegt daran, dass Ansible eine eigene Shell startet. Darüber hinaus handelt es sich um keine interaktive Login-Shell, die sich anders verhält. Beispielsweise wird die .bashrc nicht ausgeführt.

Lösung für Ansible

Um dieses Problem zu lösen, gibt es zwei Möglichkeiten. Die wohl beste ist, einfach den vollen Pfad anzugeben. Das heißt: Zu beginn definiert man eine Variable, legt den Ordner an und lädt darin die jeweiligen Binaries. In diesem Beispiel ist das die Variable „bin“ aus obigem Beispiel. Sie wird dem exa-Beispielaufruf vorangestellt:

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

Nun erhalten wir die Version der Applikation:

"stdout_lines": ["exa v0.8.0"]

Alternativ könnte man auch die Variable über Ansibles eigene Umgebungsvariablen setzen:

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

Dies gilt allerdings nur für den jeweiligen Task. Möchte man den Pfad in mehreren Tasks verwenden, müsste er jeweils erneut gesetzt werden. Das Angeben eines absoluten Pfades erscheint mir daher einfacher.

Leave a Reply