Is there a way to set ENV variable on target hosts?

The -U SUDO_USER is not really working for me because Ansible can’t find sudo. The root cause appears that it isn’t set in the target hosts bash shell $PATH variable because Ansible doesn’t seem to load in the .bash_profile or .profile

I don’t have root on the target machines to setup a sudo symbolic link in /bin/sh. Is there some way to setup Ansible to look in other places for executables besides the default PATH=/usr/bin:/bin ? The sys admins setup sudo in /usr/local/bin/ instead because that’s the standard they are using.

I tried setting sudo_exe=/usr/local/bin/sudo in ansible.cfg and it didn’t like that. Ansible just hung when I did that.

Here’s my shell output to give the idea of what’s happening on my system.

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “env”
xqa1prxy2 | success | rc=0 >>
LANG=C
SHELL=/bin/bash
SSH_CLIENT=192.168.0.13 49783 22
USER=webadm
PATH=/usr/bin:/bin
MAIL=/var/mail//webadm
_=/usr/bin/python
PWD=/export/home/webadm
TZ=US/Pacific
HOME=/export/home/webadm
SHLVL=2
LOGNAME=webadm
SSH_CONNECTION=192.168.0.13 49783 192.168.0.5 22

xqa1prxy1 | success | rc=0 >>
LANG=C
SHELL=/bin/bash
SSH_CLIENT=192.168.0.13 43491 22
USER=webadm
PATH=/usr/bin:/bin
MAIL=/var/mail//webadm
_=/usr/bin/python
PWD=/export/home/webadm
TZ=US/Pacific
HOME=/export/home/webadm
SHLVL=2
LOGNAME=webadm
SSH_CONNECTION=192.168.0.13 43491 192.168.0.4 22

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “ls -l” -U ldapadm
xqa1prxy2 | FAILED >> {
“failed”: true,
“msg”: “/bin/sh: sudo: not found\r\n”,
“parsed”: false
}

xqa1prxy1 | FAILED >> {
“failed”: true,
“msg”: “/bin/sh: sudo: not found\r\n”,
“parsed”: false
}

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “echo $PATH”
xqa1prxy1 | success | rc=0 >>
/export/home/webadm/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/app/local/bin

xqa1prxy2 | success | rc=0 >>
/export/home/webadm/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/app/local/bin

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “/usr/local/bin/sudo -h”

xqa1prxy1 | success | rc=0 >>
sudo - execute a command as another user

usage: sudo [-D level] -h | -K | -k | -V
usage: sudo -v [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-u user
name>#uid]
usage: sudo -l[l] [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-U user
name] [-u user name|#uid] [-g groupname|#gid] [command]
usage: sudo [-AbEHknPS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []
usage: sudo -e [-AknS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] file …

Options:
-a type use specified BSD authentication type
-b run command in the background
-C fd close all file descriptors >= fd
-E preserve user environment when executing command
-e edit files instead of running a command
-g group execute command as the specified group
-H set HOME variable to target user’s home dir.
-h display help message and exit
-i [command] run a login shell as target user
-K remove timestamp file completely
-k invalidate timestamp file
-l[l] command list user’s available commands
-n non-interactive mode, will not prompt user
-P preserve group vector instead of setting to target’s
-p prompt use specified password prompt
-S read password from standard input
-s [command] run a shell as target user
-U user when listing, list specified user’s privileges
-u user run command (or edit file) as specified user
-V display version information and exit
-v update user’s timestamp without running a command
– stop processing command line arguments

xqa1prxy2 | success | rc=0 >>
sudo - execute a command as another user

usage: sudo [-D level] -h | -K | -k | -V
usage: sudo -v [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-u user
name>#uid]
usage: sudo -l[l] [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-U user
name] [-u user name|#uid] [-g groupname|#gid] [command]
usage: sudo [-AbEHknPS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []
usage: sudo -e [-AknS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] file …

Options:
-a type use specified BSD authentication type
-b run command in the background
-C fd close all file descriptors >= fd
-E preserve user environment when executing command
-e edit files instead of running a command
-g group execute command as the specified group
-H set HOME variable to target user’s home dir.
-h display help message and exit
-i [command] run a login shell as target user
-K remove timestamp file completely
-k invalidate timestamp file
-l[l] command list user’s available commands
-n non-interactive mode, will not prompt user
-P preserve group vector instead of setting to target’s
-p prompt use specified password prompt
-S read password from standard input
-s [command] run a shell as target user
-U user when listing, list specified user’s privileges
-u user run command (or edit file) as specified user
-V display version information and exit
-v update user’s timestamp without running a command
– stop processing command line arguments

in playbooks each task can set variables using the environment: var=val, keyword, but I don’t think there is currently no way to do this for the ansible 1 liner.

If you need to, you can specify a different sudo binary in ansible.cfg. You might wish to fully path it there.

I have attempted that in /etc/ansible/ansible.cfg with

the default sudo executable. If a sudo alternative with a sudo-compatible interface

is used, specify its executable name as the default

#sudo_exe=sudo

sudo_exe=/usr/local/bin/sudo

Instead of breaking right away, I ended up leaving for tea and found out it’s hanging because it’s expecting inputs. I’m sure there’s something I need to set in the config to resolve this, but how is sudo called in Ansible? Better understanding it will help me figure out what flags I need to send it.

the default flags passed to sudo

sudo_flags=-H

When we switch to users, it’s by the following command, and it doesn’t prompt for a password.

xqa1prxy2$ sudo su - cqadm

This is the output of what happens after waiting long enough for Ansible & sudo to time out.

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “ls -l” -U ldapadm

xqa1prxy1 | FAILED >> {
“failed”: true,
“msg”: “[sudo via ansible, key=eijwkomkofjunxhzgdudrvwdbtvqnbfq] password: \n”,
“parsed”: false
}

xqa1prxy2 | FAILED >> {
“failed”: true,
“msg”: “[sudo via ansible, key=odyotbpwzjyoevevdqwscimdsmghoqta] password: \n”,
“parsed”: false
}

“Instead of breaking right away, I ended up leaving for tea and found out it’s hanging because it’s expecting inputs.”

–ask-sudo-pass may be your friend here.

Also make sure you’re running with a recent Ansible, Ansible 1.4 is now the latest release.

Newer versions (incl. later 1.3.X) will tell you if they get stuck waiting at a prompt in most cases.

“Instead of breaking right away, I ended up leaving for tea and found out it’s hanging because it’s expecting inputs.”

–ask-sudo-pass may be your friend here.

I did try an upgrade from 1.2 to 1.4 just in case there was an issue fixed with a newer release.

$ ansible --version

ansible 1.4 (devel 18b6372c63) last updated 2013/11/21 15:05:57 (GMT -700)

I guess perhaps sudo would need to be setup differently for it to work, like with the -u flag. A suggestion would be to include some more notes in the documentation on how to setup sudo to play well with how Ansible is executing the commands. I can’t look in the sudo config, but I believe the sysadmins only setup the following commands for us to have only access to:

sudo su - [login]

If the following was used, a password prompt would come:

sudo su [login]

sudo -u ldapadm ‘[command]’

metan@xqa1prxy1$ sudo -u ldapadm ‘ls’

Password:

metan@xqa1prxy1$ sudo su ldapadm

Password:

metan@xqa1prxy1$ sudo su - ldapadm

ldapadm@xqa1prxy1$

$ ansible --verbose -i /app/scripts/webadm/ansible/hosts proxy -a “ls -l” -U ldapadm --ask-sudo-pass
sudo password: Traceback (most recent call last):
File “/app/scripts/webadm/ansible/version/ansible-1.4/bin/ansible”, line 157, in
(runner, results) = cli.run(options, args)
File “/app/scripts/webadm/ansible/version/ansible-1.4/bin/ansible”, line 104, in run
(sshpass, sudopass) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass)
File “/app/scripts/webadm/ansible/version/ansible-1.4/lib/ansible/utils/init.py”, line 701, in ask_passwords
sudopass = getpass.getpass(prompt=sudo_prompt)
File “/usr/lib64/python2.6/getpass.py”, line 71, in unix_getpass
passwd = _raw_input(prompt, stream, input=input)
File “/usr/lib64/python2.6/getpass.py”, line 133, in _raw_input
line = input.readline()
KeyboardInterrupt

So if ad-hoc commands won’t work, I would have to see if a playbook can send a series of commands without terminating the shell for it to run. I’m only a Day 2 Ansible user and trying to investigate how it works to see how I can re-tool our scripts. :slight_smile: I appreciate all the help thus so far.

What OS are you running from?

– Michael

RHEL 6 Santiago
Linux bchopsadmp 2.6.32-279.el6.x86_64 #1 SMP Wed Jun 13 18:24:36 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

But target hosts are Solaris 10 on x86 with Python 2.6

“But target hosts are Solaris 10 on x86 with Python 2.6”

Sounds like that’s it, you just didn’t have sudo in path.

Yes, but the problem is that I can’t set the PATH to what I need it to /usr/local/bin/sudo . I had it set in .bash_profile (interactive) as well as .bashrc (non-interactive) and it still wasn’t getting the PATH set properly. It’s got way more than just /usr/bin:/bin that’s it is showing below.

webadm@bchopsadmp1$ ansible -i hosts/haqa1 proxy -a ‘env’ -u ldapadm
xqa1prxy2 | success | rc=0 >>
LANG=C
HOME=/export/home/ldapadm
LOGNAME=ldapadm
MAIL=/var/mail//ldapadm
PATH=/usr/bin:/bin
PWD=/export/home/ldapadm
SHELL=/bin/bash
SHLVL=1
SSH_CLIENT=142.52.244.208 50038 22
SSH_CONNECTION=142.52.244.208 50038 142.52.192.197 22
TZ=US/Pacific
USER=ldapadm
_=/bin/sh

xqa1prxy1 | success | rc=0 >>
LANG=C
HOME=/export/home/ldapadm
LOGNAME=ldapadm
MAIL=/var/mail//ldapadm
PATH=/usr/bin:/bin
PWD=/export/home/ldapadm
SHELL=/bin/bash
SHLVL=1
SSH_CLIENT=142.52.244.208 43746 22
SSH_CONNECTION=142.52.244.208 43746 142.52.192.192 22
TZ=US/Pacific
USER=ldapadm
_=/bin/sh

As indicated, this isn’t about setting the path, this is about configuring sudo in ansible.cfg to include the full path to the sudo executable.

This is the way this will need to be done as this all happens before executing the module, hence using Ansible to set a path is not possible.

As indicated, this isn’t about setting the path, this is about configuring sudo in ansible.cfg to include the full path to the sudo executable.

This is the way this will need to be done as this all happens before executing the module, hence using Ansible to set a path is not possible.

Yes, I did try setting it in ansible.cfg to:

#sudo_exe=sudo
sudo_exe=/usr/local/bin/sudo

The underlining question now is that does Ansible with the -U execute commands as if it was the following?

ssh [hostname] “sudo -u [username] ‘[command]’”

If it does - then I know that the root cause of the issue is because the sudoer config on my target systems is not setup to accept commands as so.

Therefore I suggest for the future, some additional notes in the documentation for first-time Ansible users on requirements of how sudo setup (via visudo) on the target host would be recommended for people in organizations that do not permit them to have root access.

Melissa,

I have this same situation and ansible’s default setup of not using a user’s login shell caught me off-guard at first to. It makes sense though for Ansible not to want to load the user’s environment in order to ensure a consistent shell experience for all modules (especially if a user has zsh as their default for example).

The solution I had to use goes against best practices but I’m in the same boat as you where I can’t change how sudo is setup on my systems as they are dictated by the enterprise. My setup goes as follows to ensure a user’s .bashrc is loaded before running any commands via the shell module:

https://gist.github.com/stevenhaddox/7628144

Hope this helps as a make-shift solution. It’s certainly not ideal, but it gets the job done. I just have to ensure I always prepend {{source_bash}} before any commands run by the shell module.

-Steven

Melissa,

I have this same situation and ansible’s default setup of not using a user’s login shell caught me off-guard at first to. It makes sense though for Ansible not to want to load the user’s environment in order to ensure a consistent shell experience for all modules (especially if a user has zsh as their default for example).

The solution I had to use goes against best practices but I’m in the same boat as you where I can’t change how sudo is setup on my systems as they are dictated by the enterprise. My setup goes as follows to ensure a user’s .bashrc is loaded before running any commands via the shell module:

https://gist.github.com/stevenhaddox/7628144

Hope this helps as a make-shift solution. It’s certainly not ideal, but it gets the job done. I just have to ensure I always prepend {{source_bash}} before any commands run by the shell module.

-Steven

Melissa,

I have this same situation and ansible’s default setup of not using a user’s login shell caught me off-guard at first to. It makes sense though for Ansible not to want to load the user’s environment in order to ensure a consistent shell experience for all modules (especially if a user has zsh as their default for example).

The solution I had to use goes against best practices but I’m in the same boat as you where I can’t change how sudo is setup on my systems as they are dictated by the enterprise. My setup goes as follows to ensure a user’s .bashrc is loaded before running any commands via the shell module:

https://gist.github.com/stevenhaddox/7628144

Hope this helps as a make-shift solution. It’s certainly not ideal, but it gets the job done. I just have to ensure I always prepend {{source_bash}} before any commands run by the shell module.

-Steven

Thanks Steven, I’ll take a look. I think I’m getting around it because I am actually allowed to ssh directly into the application account, thereby circumventing the need for sudo on some the target machines. However I may still run into other problems since the application does require PATH set. I am thinking I may get around those by using local facts and absolute paths in the commands - as some of the applications are inconsistently installed from one machine to another machine.

Michael is right about setting ansible.cfg with as sudo_exe=/usr/local/bin/sudo but I’m just facing a secondary problem now that sudo is executing.

After it is set, I’m faced with a password prompt when no password required is already done. So it is actually executing sudo, but sudo isn’t setup to authorized the command that Ansible is pushing through. The sudoers file is not very large and the Unix Sys Admins want to keep it simple… so it pretty much boils down to the following:

This might somewhat help you Stephen as you’re using zsh, but I’m just posting this for the benefit of anyone else using bash. It appears that login/non-interactive zsh shells uses .zlogin or maybe .zshenv for startup.

Problem Statement: I need to use gnu tar which is installed in /usr/local/bin/tar and not the default one in Solaris 10 (what I have on my target host) at /usr/bin/tar
Solution: For those using bash (you can set this in ansible.cfg with executable = /bin/bash ), put your $PATH settings in .bashrc instead of .bash_profile. For all other shells, make sure your $PATH variable is being set in the file that is being called for non-interactive logins.

Shown below is the shell using /usr/bin/tar - not what I want.

$ ansible -v -i hosts xqa1app3 -m shell -a ‘which tar’ -u ipadm
xqa1app3 | success | rc=0 >>
/usr/bin/tar

Checking the shell we can see the $PATH variable not having all the things I want it to see.

$ ansible -v -i hosts xqa1app3 -m shell -a ‘echo $PATH’ -u ipadm

xqa1app3 | success | rc=0 >>

/usr/bin:/bin

Taking a look at the .bashrc and .bash_profile, I know that interactive bash shells are using .bashrc and will not load .bash_profile. So I need to move the $PATH variables from .bash_profile to .bashrc

$ ansible -v -i hosts xqa1app3 -m shell -a ‘cat .bashrc’ -u ipadm
xqa1app3 | success | rc=0 >>

.bashrc

Source global definitions

if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

User specific aliases and functions

alias cdscr=‘cd /app/scripts/$USER’
alias l.=‘ls -altr’
alias ll=‘ls -l’

if [[ -z $LOGNAME ]]
then
alias cdscr=‘cd /app/scripts/$LOGNAME’
fi

$ ansible -v -i hosts xqa1app3 -m shell -a ‘cat .bash_profile’ -u ipadm
xqa1app3 | success | rc=0 >>

.bash_profile

Get the aliases and functions

if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

User specific environment and startup programs

export LD_LIBRARY_PATH=/usr/lib64

export JAVA_HOME=/usr/jdk/jdk1.6.0_45
export LDAP_HOME=/app/servers/ds/dsee7
export PATH=$JAVA_HOME/bin:$LDAP_HOME/bin:$HOME/bin:/app/local/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:$PATH

export EDITOR=vi ;

Just showing the $PATH variable before I make the changes to .bashrc so you can compare below.

$ ansible -v -i hosts xqa1app3 -m shell -a ‘echo $PATH’ -u ipadm
xqa1app3 | success | rc=0 >>
/usr/bin:/bin

I’ve now made the changes to move the $PATH variables from .bash_profile to .bashrc , we now observe that the $PATH variable has changed.

$ ansible -v -i hosts xqa1app3 -m shell -a ‘echo $PATH’ -u ipadm

xqa1app3 | success | rc=0 >>

/usr/jdk/jdk1.6.0_45/bin:/app/servers/ds/dsee7/bin:/export/home/ipadm/bin:/app/local/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:/usr/bin:/bin

Here’s what the .bashrc and .bash_profile now look like.

$ ansible -v -i hosts xqa1app3 -m shell -a ‘cat .bashrc’ -u ipadm
xqa1app3 | success | rc=0 >>

.bashrc

Source global definitions

if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

User specific aliases and functions

alias cdscr=‘cd /app/scripts/$USER’
alias l.=‘ls -altr’
alias ll=‘ls -l’

if [[ -z $LOGNAME ]]
then
alias cdscr=‘cd /app/scripts/$LOGNAME’
fi

User specific environment and startup programs

export LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH

export JAVA_HOME=/usr/jdk/jdk1.6.0_45
export LDAP_HOME=/app/servers/ds/dsee7
export PATH=$JAVA_HOME/bin:$LDAP_HOME/bin:$HOME/bin:/app/local/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:$PATH

$ ansible -v -i hosts xqa1app3 -m shell -a ‘cat .bash_profile’ -u ipadm
xqa1app3 | success | rc=0 >>

.bash_profile

Get the aliases and functions

if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

User specific environment and startup programs

#export LD_LIBRARY_PATH=/usr/lib64

#export JAVA_HOME=/usr/jdk/jdk1.6.0_45
#export LDAP_HOME=/app/servers/ds/dsee7
#export PATH=$JAVA_HOME/bin:$LDAP_HOME/bin:$HOME/bin:/app/local/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:$PATH

export EDITOR=vi ;

Success! Ansible can now call the GNU tar. As an aside, GNU tar is what module unarchive appears to expect to use on the target hosts.

The issue with this is that you’re not allowed to sudo to the target user, you’re allowed to sudo to root, then execute 'su - ’ to switch to the target user. This won’t work is you want to ‘sudo -u cmd’, as Ansible is, presumably, doing.

Ask your sysadmin to set something like the following in sudoers:

%apadm ALL=(root) sudoedit /etc/hosts
%apadm ALL=(ipadm, ldapadm, cdadm) NOPASSWD: ALL

use ~/.ssh/config to work around this, so that ssh $(somewhere) drops you right into where you want to be

e.g. for server01 where the non-root user is “jboss”. You will the private key for the user jboss on your management box.

$cat config
Host jboss-server01
Hostname server01.fqdn.com
User jboss
IdentityFile ~/.ssh/id_rsa.jboss

now, run
ssh jboss-server01

it should drop you into a shell.

you will have to set the ansible transport to be ssh in .ansible.cfg.

This can also be used to circumvent jump boxes.

I know this is an old post but if someone still sees my reply, may tell me how bad is it to do the following ( create a symbolic link in /usr/bin for sudo - it works in my solaris box):

ln -s /usr/local/bin/sudo /usr/bin/sudo

So that seems to fix the issue but it’s a very ugly fix. There should be a way to set the sudo_exe variable per server in the inventory file…