$PATH with shell is different to manual ssh

Hi,

I have been redirected from Github issue 56044.

I am finding that commands which work when run manually fail when run with a shell task, because the $PATH is different, so binaries such as ip and modinfo cannot be found.

Bcoca said:

In any case this is due to Ansible doing a batch login, which does not source the same files as a live login, this depends on your system’s configuration and can be changed by setting the PATH the same way for both types of logins.

What does that mean?
When I search online for batch logins, I get a whole bunch of irrelevant results about Windows Batch scripts.
Is this the batch you see with man batch?

How can I make an Ansible shell task execute with the same $PATH as when I ssh in manually?

I am only having this problem on a Centos target, not Ubuntu. (Perhaps the PATH is modified for Ubuntu too, but it is not impacting me because Ansible’s shell task can still find the binaries I need.)
I am already telling Ansible to use bash not sh.

Detail

Steps to reproduce

I am trying to use shell to run the modinfo binary, and also theipbinary.
I can run the command I want manually by ssh-ing into the machine.
But when I do it with Ansible, shell says “command not found”, because the $PATH is different between SSH and Ansible shell.

This happens with Ansible version 2.5 and 2.9.

My target is Centos 7.6

When I manually ssh in I see:


[centos@dell03 ~]$ which modinfo
/usr/sbin/modinfo
[centos@dell03 ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/centos/.local/bin:/home/centos/bin
[centos@dell03 ~]$ modinfo ext4 

That last command prints out a lot of text, and returns 0.

Then I try with ansible:


---
- hosts: localhost
  tasks:

    - name: check modinfo
      shell: |
         echo $PATH
         which modinfo 
         modinfo ext4
      args:
         executable: /bin/bash

**Expected results:**

  • task should pass
  • stdout should be
    /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/centos/.local/bin:/home/centos/bin

followed by a lot of text about the ext4 module

i.e. shell can find the modinfo binary because the PATH is the same as before.


**Actual Result**

fatal: [10.58.2.103]: FAILED! => {
    "changed": true,
    "cmd": "echo $PATH\nwhich modinfo\nmodinfo ext4 \n",
    "delta": "0:00:00.003893",
    "end": "2019-05-03 16:50:23.683406",
    "invocation": {
        "module_args": {
            "_raw_params": "echo $PATH\nwhich modinfo\nmodinfo ext4 \n",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": "/bin/bash",
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "msg": "non-zero return code",
    "rc": 127,
    "start": "2019-05-03 16:50:23.679513",
    "stderr": "which: no modinfo in (/usr/local/bin:/usr/bin)\n/bin/bash: line 2: modinfo: command not found",
    "stderr_lines": [
        "which: no modinfo in (/usr/local/bin:/usr/bin)",
        "/bin/bash: line 2: modinfo: command not found"
    ],
    "stdout": "/usr/local/bin:/usr/bin",
    "stdout_lines": [
        "/usr/local/bin:/usr/bin"
    ]
}

Reading the results:

echo $PATH/usr/local/bin:/usr/bin , which is not the path from before

So bash could not find the modinfo binary.

As a workaround, I am able to manually look up where the binary I want is, then prepend "$PATH=$PATH:/usr/sbin " to my shell command. That works, but is not scalable.

tldr, how can I make the shell task use the same $PATH as a normal ssh login?

Thanks,
Matt

I think the key terms here are likely interactive vs non-interactive shells.

A bashrc or bash profile may have lines that look like:

If not running interactively, don’t do anything

[ -z “$PS1” ] && return

or

If not running interactively, don’t do anything

case $- in
i) ;;
*) return;;
esac

This prevents those files from running in a non-interactive shell, and those files, from a global perspective, source other files including your personal rc or profile files.

As such, since ansible uses non-interactive shells, you will often have a different shell environment when interactively logged in.

Ah yes, I see that bit in .bashrc.

Is there any way to open an interactive shell, but source .bashrc as a non-interactive shell?
I just want to be able to emulate the environment Ansible runs in.

I tried

PATH="" PS1="" . /home/centos/.bashrc ; echo $PATH

But that didn’t work

Thanks,
Matt

I deal with a lot of legacy systems that don’t always have great path defaults for working with Ansible. I ended up putting the following at the top of my main playbook to add some common locations to the path if they were not present. Might help in your case if you can’t easily modify the standard profiles. it seems to work well.

Ah yes that works.

Thanks!

And for those who are wondering, I found a way to emulate the non-interactive environment. Just run commands via ssh inline.

e.g.

ssh centos@10.1.1.2 ./yourCommand here

Regards,
Matt