当我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
命令(如service
, ntpdate
等)时会导致问题,因为它需要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/bash
shell中看到的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 command
或ansible -s
,用户环境重置,$ PATH由/etc/sudoers
的Default 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"