exec $ SHELL从SSH执行,不会在剧本中执行 [英] exec $SHELL executes from SSH, won't execute in playbook

查看:120
本文介绍了exec $ SHELL从SSH执行,不会在剧本中执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在来宾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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆