为什么'ansible -a'env''返回一个不同于我的用户的环境path?

当我SSH入远程服务器并运行env我回来以下path

 PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/myusername/bin 

相反,当我执行ansible- ansible -a "env"命令时,我得到以下path:

 PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin 

可以想象,当尝试运行sbin命令(如servicentpdate等)时会导致问题,因为它需要inputsbin命令的完整path。 (是的,我知道有一些可行的模块可以做到这一点,但我试图解决为什么PATH正在缩短/截断。)

任何人都知道这是为什么发生?

编辑:我问这个问题的原因是,我正在阅读Ansible for DevOps一书中的例子,因为这个原因,一些例子没有工作。

我试图去做的例子是从书中的第28页开始的:

 $ ansible multi -s -a "service ntpd stop" $ ansible multi -s -a "ntpdate -q 0.rhel.pool.ntp.org" $ ansible multi -s -a "service ntpd start" 

这些命令总是会引发错误。 但是,如果我改变他们包括完整的path,他们的工作。

 $ ansible multi -s -a "/sbin/service ntpd stop" $ ansible multi -s -a "/usr/sbin/ntpdate -q 0.rhel.pool.ntp.org" $ ansible multi -s -a "/sbin/service ntpd start" 

当然,我不希望input我发出的每个ad-hoc命令的完整path。 (我不知道每个命令的path。)

有什么办法可以让我的shell中包含正常的path吗? 有一个pathvariables,我可以添加到清单文件或ansible.cfg文件,将使这发生?

任何时候我使用ansible作为一个不同的用户运行..下一个不同的shell。 应该能够看到在做什么用户:

ansible -a "id"

然后你可以看到cat /etc/passwd定义的用户shell

添加到path中的最佳做法是在/home/<username>/.profile ~/.bash_profile添加一行

ansible -a正在使用命令模块 ,并且不使用shell来执行命令。

http://docs.ansible.com/ansible/intro_adhoc.html
通常情况下,命令也会使用-m作为模块名称,但默认的模块名称是“command”。

/usr/sbin这样的path组件会通过shell来源/etc/profile文件添加到path中,而命令模块不会创buildlogin shell,因此不会读取该文件。

http://linux.die.net/man/1/bash
当bash作为交互式loginshell或者作为具有–login选项的非交互式shell调用时,它首先从文件/ etc / profile中读取和执行命令(如果该文件存在)。 读取该文件后,它将按照该顺序查找〜/ .bash_profile,〜/ .bash_login和〜/ .profile,并从第一个存在并读取的第一个中读取和执行命令。 当shell开始禁止这种行为时,可以使用–noprofile选项。

可靠的文档说,如果你想要一个shell,使用shell模块。 然而,似乎没有一个选项可以从shell模块启动loginshell(通过传递–login选项)。

事实上,在不同的地方都提到了这样的策略:不信任环境,在定义任务时明确地设置VARS。

但是,可以在ad-hoc模式下使用ansible时设置path。 这些是我可以做到的最接近复制在交互式/bin/bashshell中看到的PATH;

 $ ansible raspberrypi -m shell \ -a 'PATH=$PATH:/usr/local/sbin:/usr/sbin:$HOME/bin env' \ | grep PATH PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/sbin: /usr/sbin:/home/pi/bin 

或者,您可以input/etc/profile文件;

  $ ansible raspberrypi -m shell \ -a 'executable=/bin/bash source /etc/profile ; env | grep PATH' PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin: /usr/sbin:/usr/bin:/sbin:/bin 

这似乎也工作;

 $ ansible raspberrypi -a '/bin/bash -l -c "env"' PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin: /usr/sbin:/usr/bin:/sbin:/bin 

所以,考虑到你的问题最终是关于在sudo下运行命令,我又看了一下在使用ansible -s -a env时如何设置PATH。 我认为注意到在使用sudo -s标志的时候,$ PATH是通过一个不同的机制来设置的,当只使用ansible -a env

当使用sudo commandansible -s ,用户环境重置,$ PATH由/etc/sudoersDefault secure_path设置控制,这在man sudoers文档中有解释;

默认情况下,启用env_reset选项。 这会使命令在新的最小环境下执行。 除了env_check和env_keep选项允许的调用过程的variables以外,新环境还包含TERM,PATH,HOME,MAIL,SHELL,LOGNAME,USER,USERNAME和SUDO_ *variables。

如果您没有为Default secure_path设置一个值,那么这些值将被硬编码到sshd二进制文件中,请参阅此答案以获取详细信息。

但是在fedora / centros / ubuntu上,默认情况下,$ PATH的值取自/etc/sudoers设置的secure_path;

secure_path – 从sudo运行的每个命令使用的path。

例如在我的Fedora本地主机上,它在/etc/sudoers有以下行

 Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin 

如果我通过ssh和sudo远程运行env命令,则会返回确切的path;

 $ ssh localhost "sudo env" | grep PATH PATH=/sbin:/bin:/usr/sbin:/usr/bin 

我用同样的方法得到同样的东西。

 $ ansible localhost -s -a 'env' | grep PATH PATH=/sbin:/bin:/usr/sbin:/usr/bin 

我在一个raspbian(debian)实例上尝试过同样的事情,而且我得到了类似的行为。

 $ ansible raspberrypi -s -a 'cat /etc/sudoers' | grep secure Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 

这是人们用-s -a选项看到的path;

 $ ansible raspberrypi -s -a env | grep PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 

所以就你原来的问题,我会看看/etc/sudoers文件,并检查Defaults secure_path="/some/path/here"

如果你没有一个包含合适的sbin/目录的值,那么在没有给出完整path的情况下,下面的ansible命令将不起作用;

 ansible multi -s -a "service ntpd stop"