exec $ SHELL从SSH执行,不会在剧本中执行 [英] exec $SHELL executes from SSH, won't execute in playbook
问题描述
我正在尝试在来宾VM上配置Ruby + Rails.这是我的playbook.yml
中的内容:
I'm trying to provision Ruby + Rails on a guest VM. Here's what I have in my playbook.yml
:
---
- hosts: all
sudo: true
tasks:
- apt: update_cache=yes
- apt: name={{ item }} state=present
with_items:
- build-essential
- git-core
- zlib1g-dev
- libssl-dev
- libreadline-dev
- libmysqlclient-dev
- libyaml-dev
- libxml2-dev
- libxslt1-dev
- libcurl4-openssl-dev
- python-software-properties
- libffi-dev
- curl
- command: git clone git://github.com/sstephenson/rbenv.git .rbenv
- shell: echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
- shell: echo 'eval "$(rbenv init -)"' >> ~/.bashrc
- shell: exec $SHELL
- command: git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
- shell: echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
- shell: exec $SHELL
- command: git clone https://github.com/sstephenson/rbenv-gem-rehash.git ~/.rbenv/plugins/rbenv-gem-rehash
- command: rbenv install 2.2.3
- command: rbenv global 2.2.3
- shell: echo 'gem{{":"}} --no-ri --no-rdoc' >> ~/.gemrc
- command: gem install bundler
- command: add-apt-repository -y ppa:chris-lea/node.js
- apt: update_cache=yes
- apt: name=nodejs state=present
- command: gem install rails -v 4.2.2
- command: rbenv rehash
配置时,Ansible始终挂在任务- shell: exec $SHELL
上,并且不返回.但是,当我通过SSH进入计算机并运行exec $SHELL
时,它将执行并返回.当我在剧本中使用- command: exec $SHELL
时,Ansible会显示此错误:
When provisioning, Ansible always hangs at task - shell: exec $SHELL
and doesn't return. But when I SSH into the machine and run exec $SHELL
, it executes and returns. When I use - command: exec $SHELL
instead in my playbook, Ansible prints this error:
failed: [default] => {"cmd": "exec /bin/bash", "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory
我可以确认/bin/bash
存在.
这是怎么回事?我已经为此苦了半天.请告知.
What's going on? I've been struggling with this for half a day now. Please advise.
推荐答案
首先,我不建议您执行以下操作:
Well first of all I wouldn't recommend that you do things like this:
- shell: echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
- shell: echo 'eval "$(rbenv init -)"' >> ~/.bashrc
如果您碰巧在主机上多次运行此剧本,那么您最终将在不需要的.bashrc文件中得到每个命令的多个实例.您应该考虑模板化您的.bashrc文件,或者至少使用类似 lineinfile ,以确保这些条目仅添加一次.
If you happen to run this playbook against a host multiple times then you'll end up with multiple instances of each of these commands in your .bashrc file, which you don't want. You should consider templating your .bashrc file, or at the very least using something like lineinfile to make sure these entries are added only once.
就此任务而言:
- shell: exec $SHELL
这是您绝对不应该做的事情.这肯定不会达到您期望的结果,并且表明您不完全了解任务(尤其是Shell任务)的工作方式. exec
用指定的命令替换退出的shell.如果尝试执行此操作时未收到错误,则您实际上要执行的操作是替换Ansible启动的shell以运行此命令.从理论上讲,Ansible启动的外壳将替换为另一个外壳,然后Ansible将挂起,因为它等待外壳终止,但是您执行的外壳没有执行任何操作,因此它将永远不会终止.
This is something you simply should never do. This certainly won't have the result you may be expecting, and it indicates that you don't fully understand how tasks (and in particular the shell task) work. exec
replaces the exiting shell with the specified command. If you didn't get an error when attempting this then what you would effectively be doing is replacing the shell launched by Ansible to run this command. What would theoretically happen is that the shell Ansible launches gets replaced with another shell, and Ansible would then simply hang because its waiting for the shell to terminate, but the shell you exec'd isn't doing anything so it will never terminate.
一旦执行了此任务,您的剧本就不会继续运行.您可能需要按ctrl + c来终止ansible-playbook,或者需要登录到远程主机并杀死ansible正在等待的shell,这时由于任务失败,该playbook将会终止.
Once this task executed your playbook wouldn't continue running. You would either need to ctrl+c to terminate ansible-playbook, or you'd need to log into the remote host and kill the shell ansible is waiting on, at which point the playbook would terminate due to the task failing.
将其切换为-command: shell $SHELL
也会失败,因为exec
是内置的shell命令,但作为
Switching this to -command: shell $SHELL
also fails because exec
is a built-in shell command, but as the Ansible documentation for the command module states:
给定的命令...将不会通过外壳处理
The given command ... will not be processed through the shell
由于command
模块直接而不是通过外壳执行命令,因此无法识别外壳内置的exec
之类的内容.这就是为什么您收到上面指示的错误消息的原因.
Since the command
module is executing the command directly and not through a shell then shell built-in's like exec
won't be recognized. This is why you get the error message that you indicated above.
也许您应该详细说明您要做什么以及为什么您认为需要以这种方式调用exec $SHELL
.
Perhaps you should provide a detailed explanation of what you're trying to do and why you think you need to be invoking exec $SHELL
in this manner.
您还应该考虑更改以下任务:
You should also consider changing tasks like these:
- command: gem install bundler
改为使用 Ansible gem模块.通常,您希望在任何可能的地方使用内置的Ansible模块,并且仅将shell/command等用作最后的选择.内置模块可提供更好的错误处理,参数验证等.
to use the Ansible gem module instead. In general you want to use the built-in Ansible modules wherever possible, and only use shell/command, etc. as a last resort. The built-in modules provide better error handling, parameter validation, etc. among other things.
这篇关于exec $ SHELL从SSH执行,不会在剧本中执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!