为什么 'ansible -a“env”' 返回与我的用户不同的环境 PATH?

为什么 'ansible -a“env”' 返回与我的用户不同的环境 PATH?

当我通过 ssh 进入远程服务器并运行时,env我得到了以下路径:

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命令时会导致问题,因为它需要输入 sbin 命令的完整路径。 (是的,我知道有 ansible 模块可以做到这一点,但我正在尝试解决为什么 PATH 会缩短/截断。)servicentpdate

有人知道为什么会发生这种情况吗?

编辑:我之所以询问这个问题是因为我正在遵循书中的例子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"

这些命令总是会引发错误。但如果我将它们更改为包含完整路径,它们就会起作用。

$ 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"

当然,我不想必须输入我发出的每个临时命令的完整路径。(我不知道每个命令的路径。)

有什么方法可以让我的 shell 中的正常路径包含在 ansible 中吗? 是否有一个路径变量可以添加到 inventory 文件或 ansible.cfg 文件中以实现这一点?

答案1

任何时候我使用 ansible,它都会以不同的用户身份运行..在不同的 shell 下。应该能够通过执行以下操作来查看用户:

ansible -a "id"

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

添加路径的最佳做法是添加一行: /home/<username>/.profile 或者 ~/.bash_profile

答案2

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

http://docs.ansible.com/ansible/intro_adhoc.html
通常命令也采用 -m 作为模块名称,但默认模块名称是“命令”。

路径的组成部分,例如/usr/sbin由 shell 采购文件添加到路径中/etc/profile,而命令模块不会创建登录shell 所以它不会读取该文件。

http://linux.die.net/man/1/bash
当 bash 作为交互式登录 shell 或使用 --login 选项作为非交互式 shell 调用时,它首先从文件 /etc/profile 中读取并执行命令(如果该文件存在)。读取该文件后,它会按顺序查找 ~/.bash_profile、~/.bash_login 和 ~/.profile,然后从第一个存在且可读的文件中读取并执行命令。启动 shell 时可以使用 --noprofile 选项来禁止此行为。

ansible 文档说,如果你想要一个 shell,可以使用模块。但是,似乎没有从 shell 模块启动登录 shell 的选项(通过传递 --login 选项)。

事实上,在很多地方都提到,ansible 策略是不信任环境,并在定义任务时明确设置任何 VARS。

但是,在 ad-hoc 模式下使用 ansible 时可以设置路径。这些是我能做的最接近复制您在交互式/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

或者您也可以获取该/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

答案3

因此,鉴于您的问题最终是关于使用 ansible 在 sudo 下运行命令,我再次查看了使用时如何设置 PATH ansible -s -a env。我认为重要的是要注意,-s在 ansible 中使用 sudo 标志时,$PATH 的设置机制与仅使用时不同ansible -a env

当使用sudo command或用户环境被重置时,$PATH 由中的设置ansible -s控制,这在Default secure_path/etc/sudoers人 sudoers文档;

默认情况下,env_reset 选项处于启用状态。这将导致使用新的最小环境执行命令。新环境包含 TERM、PATH、HOME、MAIL、SHELL、LOGNAME、USER、USERNAME 和 SUDO_* 变量,以及 env_check 和 env_keep 选项允许的调用进程的变量。

如果你没有设置值Default secure_path,那么这些值将被硬编码到 sshd 二进制文件中,请参阅这个答案了解详情。

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

secure_path-从 sudo 运行的每个命令使用的路径。

例如,在我的 fedora localhost 上,有以下行/etc/sudoers

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

如果我env通过 ssh 和 sudo 远程运行该命令,我会得到该精确的路径;

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

我使用 ansible 也得到了同样的结果;

$ 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"

这就是 ansible 通过选项看到的路径-s -a

$ 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/,那么在没有给出完整路径的情况下,ansible 中的以下命令将无法工作;

ansible multi -s -a "service ntpd stop"

相关内容