Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shell module does not use the remote user's default shell #1238

Closed
srgvg opened this issue Oct 5, 2012 · 36 comments

Comments

Projects
None yet
@srgvg
Copy link
Member

commented Oct 5, 2012

I'm doing a local_action: shell command
the docs state on the shell module:" runs the command through the user’s configured shell "
in my test, local user is root, has bash as its shell, but the action seems to be run by /bin/sh instead

the shell code snippet contains bash specific stuff and hence fails, I had to explicitly run bash:

  • name: get peer name
    local_action: shell bash -c 'H=${ansible_hostname} && [ ${H#${H%?}} = 1 ] && echo ${H/%-1/-2} || echo ${H/%-2/-1}'
    register: peer_name

running ansible 0.8 (devel 565f336) last updated 2012/09/11 10:58:32 (GMT +200)

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Oct 5, 2012

I suspect it was just failing due to you needing to quote things, but you also didn't specify your OS. We are not explicitly selecting /bin/sh and the shell module does use shell=True as an argument to subprocess.

On most Linux systems:

ls -l /bin/sh

lrwxrwxrwx. 1 root root 4 Dec 16 2011 /bin/sh -> bash

@mpdehaan mpdehaan closed this Oct 5, 2012

@srgvg

This comment has been minimized.

Copy link
Member Author

commented Oct 5, 2012

Running Ubuntu where sh = dash

I'm not sure what more should be quoted, this runs fine under bash:

local_action: shell H=${ansible_hostname} && [ ${H#${H%?}} = 1 ] && echo ${H/%-1/-2} || echo ${H/%-2/-1}

gives this error:

failed: [nme-inventaris-pr-2-mgt] => {"changed": true, "cmd": "H=nme-inventaris-pr-2 && [ ${H#${H%?}} = 1 ] && echo ${H/%-1/-2} || echo ${H/%-2/-1} ", "delta": "0:00:00.001841", "end": "2012-10-05 14:59:07.097736", "rc": 2, "start": "2012-10-05 14:59:07.095895", "stderr": "/bin/sh: 1: Bad substitution", "stdout": ""}

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Oct 5, 2012

So apparently Python subprocess uses /bin/sh and not shell settings, and there is an executable= that can be used to specify another shell.

http://www.saltycrane.com/blog/2011/04/how-use-bash-shell-python-subprocess-instead-binsh/

I would propose a patch be added to allow the shell module to take a shell= flag that works in the same way creates/removes is processed, should be easy to add.

@nengxu

This comment has been minimized.

Copy link

commented Oct 25, 2012

Michael, you seemed to close issues too quickly ;-) Tonight I tried to use Ansible for the first time, using playbook for a very simple task, update rvm.
tasks:
- name: periodically update rvm
action: shell rvm get head

Encountered this same kind of error:
stderr: /bin/sh: rvm: command not found

Not a very good first impression of Ansible ;-) Could you please do what you proposed: "should be easy to add"?

Right now I have to go back to Fabric. Sorry.

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Oct 25, 2012

Hmm.

Seems like you could just fully path rvm.

@nengxu

This comment has been minimized.

Copy link

commented Oct 25, 2012

A simple rule for good tool is to make simple things no-brainer, and to
make difficult things easier. Not to make simple things complicate or
harder. In normal use case, will you always fully path every command?
Note the actual location of a command may be different on different
systems.

On Thu, 25 Oct 2012 04:01:39 -0700
Michael DeHaan notifications@github.com wrote:

Hmm.

Seems like you could just fully path rvm.


Reply to this email directly or view it on GitHub:
#1238 (comment)

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Oct 25, 2012

Just giving you a workaround. Still no idea why you are having path
issues, will explore later.

@nengxu

This comment has been minimized.

Copy link

commented Oct 25, 2012

Thanks for your quick response. For your information, I was running the
task as myself on localhost. And like many people, I'm using bash.

On Thu, 25 Oct 2012 09:08:21 -0700
Michael DeHaan notifications@github.com wrote:

Just giving you a workaround. Still no idea why you are having path
issues, will explore later.


Reply to this email directly or view it on GitHub:
#1238 (comment)

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2012

I am not quite sure if this is the place to weigh in, let me know if not and I'll open another bug. I just installed ansible to try it out because it looks very nice, and it won't work. It always gives me:

FAILED => failed to transfer file to ^/file

This is because I'm using fish as my shell (changing to bash works fine), so maybe it would not be that great if ansible used the user's shell by default, especially when it assumes sh-compatibility (or at least that's what I think it assumes?).

Maybe it could be a configuration option?

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 2, 2012

Actually, this is starting to be a problem for me. Should I open another issue for this?

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Nov 2, 2012

Are you using the 0.9 branch? We're already executing /bin/sh directly
now, so your problem should have gone away already.

Can you share the output of:

ansible --version

AND

-v -v -v

??

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 9, 2012

I am indeed, although it seems to not be shell-related. However, when I change my default shell from fish to bash, everything works.

Here's the output for when it breaks:

(env)username@computer ~/C/deployment> ansible --version
ansible 0.9

(env)username@computer ~/C/deployment> ansible-playbook -v -v -v -i hosts -K apache.yml
sudo password: 

PLAY [webservers] ********************* 

TASK: [Upload the configuration file.] ********************* 
<support.com> ESTABLISH CONNECTION FOR USER: username on PORT 22 TO support.com
<support.com> EXEC /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-1352499018.87-247197195372620 && chmod a+rx $HOME/.ansible/tmp/ansible-1352499018.87-247197195372620 && echo $HOME/.ansible/tmp/ansible-1352499018.87-247197195372620'
<support.com> PUT /tmp/tmpoUAIe3 TO /home/username/.ansible/tmp/ansible-1352499018.87-247197195372620/source
<support.com> PUT /tmp/tmpWWIaHB TO /home/username/.ansible/tmp/ansible-1352499018.87-247197195372620/copy
<support.com> EXEC sudo -k && sudo -p "[sudo via ansible, key=mggyqckxchpuzjstkcksfykojtekbvaq] password: " -u root /bin/sh -c '/usr/bin/python /home/username/.ansible/tmp/ansible-1352499018.87-247197195372620/copy; rm -rf /home/username/.ansible/tmp/ansible-1352499018.87-247197195372620/ >/dev/null 2>&1'
fatal: [support.com] => ssh connection closed waiting for password prompt

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************* 
support.com      : ok=0    changed=0    unreachable=1    failed=0
@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Also:

<staging> EXEC sudo -k && sudo -p "[sudo via ansible ... " -u root /bin/sh -c '/usr/bin/python /home/ansible-1353606252.84-175948080197889/command; rm -rf /home/ansible-1353606252.84-175948080197889/ >/dev/null 2>&1'
fatal: [staging] => failed to parse: fish: Expected a command name, got token of type “Run job in background”. Did you mean “COMMAND; and COMMAND”? See the help section for the “and” builtin command by typing “help and”.

This is because ansible assumes && will work, when it doesn't. I suggest you split sudo -k and sudo -p into two lines.

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Changing && to ; works with fish.

@dhozac

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

But doesn't have the same meaning or result.

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Well, it depends on whether you want it to fail sometimes or all the time.

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Splitting them would be inefficient. Twice as many invocations. Quit using a weird shell? In the worst case, ansible_shell_sep as a variable?

-- Michael

On Nov 22, 2012, at 12:48 PM, Stavros Korokithakis notifications@github.com wrote:

Also:

EXEC sudo -k && sudo -p "[sudo via ansible ... " -u root /bin/sh -c '/usr/bin/python /home/ansible-1353606252.84-175948080197889/command; rm -rf /home/ansible-1353606252.84-175948080197889/ >/dev/null 2>&1'
fatal: [staging] => failed to parse: fish: Expected a command name, got token of type “Run job in background”. Did you mean “COMMAND; and COMMAND”? See the help section for the “and” builtin command by typing “help and”.
This is because ansible assumes && will work, when it doesn't. I suggest you split sudo -k and sudo -p into two lines.


Reply to this email directly or view it on GitHub.

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

"Quit using a weird shell"? Is that seriously your resolution to this bug?

Anyway, what's wrong with sudo -k; sudo -p? How are you expecting sudo -k to fail?

@mpdehaan

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

No, that was half in jest, but we should not swallow errors.

On Nov 22, 2012, at 1:31 PM, Stavros Korokithakis notifications@github.com wrote:

"Quit using a weird shell"? Is that seriously the resolution to this bug?

Anyway, what's wrong with sudo -k; sudo -p? How are you expecting sudo -k to fail?


Reply to this email directly or view it on GitHub.

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

No, that was half in jest

Ah, it was half-said to me in the IRC channel, so I'm a bit defensive about it :P

What's sudo -k used for? Isn't it even better if the user's credentials aren't invalidated? Or is it so ansible can expect a prompt each time?

@dhozac

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Fix has already been pushed for this, although it's not really related to this bug.

@skorokithakis

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2012

Great, thank you.

@lvonk

This comment has been minimized.

Copy link

commented Jun 28, 2013

Hi,

Is this bash issue now fixed? Is it already possible to configure I want to use bash instead of sh?

Thanks, Lars

@saizai

This comment has been minimized.

Copy link

commented Jun 14, 2014

Still not fixed:

TASK: [Get gem version] *******************************************************
failed: [mylfrontend] => {"changed": true, "cmd": "gem -v ", "delta": "0:00:00.004823", "end": "2014-06-14 21:08:48.955209", "rc": 127, "start": "2014-06-14 21:08:48.950386"}
stderr: /bin/sh: 1: gem: not found

... and that's with executable = /bin/bash in ansible.cfg, and the runas user having /bin/bash as default shell.

@imendi

This comment has been minimized.

Copy link

commented Oct 3, 2014

a workaround to this is to save a sh wrapper in some place and call rvm from it.

wrapper

 #!/bin/bash
 source /home/ubuntu/.rvm/scripts/rvm && $*

i saved it in /usr/local/bin and chmod +x it
and in the playbook

- name: periodically update rvm
   shell:  wrapper get head
@bbakersmith

This comment has been minimized.

Copy link

commented Feb 12, 2015

This is still broken, I cannot get the shell module to use bash. Why has this issue never been re-opened?

@tjanez

This comment has been minimized.

Copy link
Contributor

commented Mar 5, 2015

@bbakersmith, agreed. Is there any work-around to to specify which shell the shell module should use?

For example, I would need to use Bash instead of default Dash on Debian-based systems.

@bcoca

This comment has been minimized.

Copy link
Member

commented Mar 5, 2015

in ansible.cfg, you can set 'executable' to a specific shell

Brian Coca

@tjanez

This comment has been minimized.

Copy link
Contributor

commented Mar 5, 2015

@bcoca, thanks for a quick reply.

I tried it but it didn't work. I'm using ansible-1.8.4-1.fc20.noarch on Fedora 20, the target system is a Debian 7.8.0 machine. My ansible.cfg is:

[defaults]
executable = /bin/bash
log_path = ../.tmp/ansible.log
hash_behaviour = merge
error_on_undefined_vars = yes
host_key_checking=False

This is the output of a failing task:

Perform task: check if DH parameter file suits the private key (y/n/c):  *** 
<commented-out> 
<commented-out> ==
<commented-out> ConnectTimeout=10 PasswordAuthentication=no KbdInteractiveAuthentication=no User=genialis ControlPath=/home/tadej/.ansible/cp/ansible-ssh-%h-%p-%r PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey StrictHostKeyChecking=no ControlMaster=auto Port=22 ControlPersist=60s
<commented-out> 
<commented-out> ConnectTimeout=10 'sudo -k && sudo -H -S -p "[sudo via ansible, key=sbenardfpqtzyjqsjvrmmqldhrjizhnq] password: " -u root /bin/bash -c '"'"'echo SUDO-SUCCESS-sbenardfpqtzyjqsjvrmmqldhrjizhnq; LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /home/genialis/.ansible/tmp/ansible-tmp-1425572474.52-157166051370756/command; rm -rf /home/genialis/.ansible/tmp/ansible-tmp-1425572474.52-157166051370756/ >/dev/null 2>&1'"'"'' PasswordAuthentication=no KbdInteractiveAuthentication=no User=genialis ControlPath=/home/tadej/.ansible/cp/ansible-ssh-%h-%p-%r PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey StrictHostKeyChecking=no ControlMaster=auto Port=22 ControlPersist=60s
ok: [main.cloud.g] => {"changed": false, "cmd": "(( $( [[ -e /etc/ssl/localcerts/dhparam.pem ]] && ( openssl dhparam -in /etc/ssl/localcerts/dhparam.pem -noout -text | grep 'DH Parameters' | sed -r 's/.*DH Parameters[^0-9]*([0-9]+)[^0-9]*/\\1/' ) ) == 2048 )) && echo 'OK' || echo 'Not suitable'", "delta": "0:00:00.006077", "end": "2015-03-05 17:21:14.736773", "rc": 0, "start": "2015-03-05 17:21:14.730696", "stderr": "/bin/sh: 1: [[: not found\n/bin/sh: 1: ==: not found", "stdout": "Not suitable", "stdout_lines": ["Not suitable"], "warnings": []}
@bcoca

This comment has been minimized.

Copy link
Member

commented Mar 5, 2015

here its used: root /bin/bash -c

Brian Coca

@tjanez

This comment has been minimized.

Copy link
Contributor

commented Mar 6, 2015

@bcoca, yes I see /bin/bash -c ..., but unfortunately that doesn't help.

The problem lies in the last line:
... "stderr": "/bin/sh: 1: [[: not found\n/bin/sh: 1: ==: not found", ...

Do you have any idea why /bin/sh is being used (both the user that is used for the connection (genialis) and root have bin/bash set as the shell in /etc/passwd)?

The problem is that on Debian systems /bin/sh points to Dash, which doesn't support the features I need. That's why I would like to replace /bin/sh with /bin/bash. Any pointers on how to do that?

@bcoca

This comment has been minimized.

Copy link
Member

commented Mar 6, 2015

Some commands will always use /bin/sh as it is hardcoded, I've never seen a
(non windows) system w/o a /bin/sh (it is required by POSIX). executable
lets you set the shell module execution, but does not govern other actions
ansible takes.

Brian Coca

@tjanez

This comment has been minimized.

Copy link
Contributor

commented Mar 6, 2015

@bcoca,

after reading the shell module documentation again I realized that I completely missed the executable parameter that can be passed to it. After setting it to executable: "/bin/bash", everything works as expected.

Thanks for you patience and helping me resolve this issue!

@komuw

This comment has been minimized.

Copy link

commented Mar 6, 2016

@tjanez +1

@pilaas

This comment has been minimized.

Copy link

commented Mar 23, 2016

Is it possible to set /bin/bash as a default shell for all tasks using shell module or modules which are invoked ? executable = /bin/bash in ansible.cfg doesn't work. My problem is that I am installing npm using module in first task. The next task (which uses npm module) can't find npm command.

@gi2r2ig

This comment has been minimized.

Copy link

commented Mar 13, 2019

Not sure if this got solved ever!!
running ansible version (2.4.2.0) and getting same issues.
bash-4.2$ ansible all -i server, -m shell -a "ip link" -k -b -K
SSH password:
SUDO password[defaults to SSH password]:
server | FAILED | rc=127 >>
/bin/sh: ip: command not found

my path variable has /usr/sbin, which "ip link" needs. It runs perfectly fine when i login to the server and execute command.
bash-4.2$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
bash-4.2$ which ip
/usr/sbin/ip
Howerver, it fails using ansible. I know solution is to run "/usr/sbin/ip link". But do we really need to do that? shouldn't ansible use users default path variable? I can't imagine using full path for every commands that ansible doesn't like it.

@ansible ansible locked and limited conversation to collaborators Apr 24, 2019

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.