13

I'm asking myself why Ansible doesn't source ~/.profile file before execute template module on one host ?

Distant host ~/.profile:

export ENV_VAR=/usr/users/toto

A single Ansible task:

- template: src=file1.template dest={{ ansible_env.ENV_VAR }}/file1

Ansible fail with:

fatal: [distant-host] => One or more undefined variables: 'dict object' has no attribute 'ENV_VAR'
pierrefevrier
  • 1,570
  • 4
  • 22
  • 33

8 Answers8

16

Ansible is not running remote tasks (command, shell, ...) in an interactive nor login shell. It's same like when you execute command remotely via 'ssh user@host "which python"' To source ~/.bashrc won't work often because ansible shell is not interactive and ~/.bashrc implementation by default ignores non interactive shell (check its beginning).

The best solution for executing commands as user after its ssh interactive login I found is:

- hosts: all
  tasks:
    - name: source user profile file
      #become: yes
      #become_user: my_user  # in case you want to become different user (make sure acl package is installed)
      shell: bash -ilc 'which python' # example command which prints
      register: which_python
    - debug:
      var: which_python

bash: '-i' means interactive shell, so .bashrc won't be ignored '-l' means login shell which sources full user profile (/etc/profile and ~/.bash_profile, or ~/.profile - see bash manual page for more details)

Explanation of my example: my ~/.bashrc sets specific python from anaconda installed under that user.

Juraj Michalak
  • 1,138
  • 10
  • 9
  • this worked for me (and `-c` reads options from the string) – uroboros Jul 08 '21 at 16:11
  • it works, though complains a little to stderr: "bash: cannot set terminal process group (70071): Inappropriate ioctl for device\nbash: no job control in this shell" – shomeax Nov 30 '21 at 20:43
8

Ansible is not running tasks in an interactive shell on the remote host. Michael DeHaan has answered this question on github some time ago:

The uber-basic description is ansible isn't really doing things through the shell, it's transferring modules and executing scripts that it transfers, not using a login shell.

i.e. Why does an SSH remote command get fewer environment variables then when run manually?

It's not a continous shell environment basically, nor is it logging in and typing commands and things.

You should see the same result (undefined variable) by running this:

ssh <host> echo $ENV_VAR
Community
  • 1
  • 1
udondan
  • 57,263
  • 20
  • 190
  • 175
5

In a lot of places I've used below structure:

- name: Task Name
  shell: ". /path/to/profile;command"
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
itiic
  • 3,284
  • 4
  • 20
  • 31
1

when ansible escalates the privilige to sudo it don't invoke the login shell of sudo user

we need to make changes in the way we call sudo like invoking it with -i and -H flags

"sudo_flags=-H" in your ansible.cfg file

Sharath Arakere
  • 129
  • 2
  • 9
0

If you can run as root, you can use runuser.

- shell: runuser -l '{{ install_user }}' -c "{{ cmd }}"

This effectively runs the command as install_user in a fresh login shell, as if you had used su - *install_user* (which loads the profile, though it might be .bash_profile and not .profile...) and then executed *cmd*.

I'd try not to run everything as root just so you can run it as someone else, though...

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
0

If you can modify the configuration of your target host and don't want to change your ansible yaml code. You can try this:
add the variable ENV_VAR=/usr/users/toto into /etc/environment file rather than ~/.profile.

R.Liu
  • 361
  • 3
  • 6
0
  shell: "bash -l scala -version"

by using bash -l will allow ansible to load corresponding bash_profile.

bash: '-i' (interactive shell) won't allow the ansible to run other task.

0

add the variable ENV_VAR=/usr/users/toto into /etc/environment file rather than ~/.profile.

You really can use /etc/environment, but only if a variable has a static value. If we use variable which gets the value of another variable it doesn't work. For example, if we put this line to /etc/environment

XDG_RUNTIME_DIR=/run/user/$(id -u)

Ansible can see exactly XDG_RUNTIME_DIR=/run/user/$(id -u), not XDG_RUNTIME_DIR=/run/user/1012.

And if we put this line to ~/.bash_profile or ~/.bashrc:

export XDG_RUNTIME_DIR=/run/user/$(id -u)

User can see XDG_RUNTIME_DIR=/run/user/1012 (if user's id is 1012) when he works manually, but Ansible doesn't get variable XDG_RUNTIME_DIR at all.

bestann
  • 11
  • 1
  • 3