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

查看:28
本文介绍了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 启动的 shell 被另一个 shell 替换,然后 Ansible 会挂起,因为它在等待 shell 终止,但是您执行的 shell 没有做任何事情,所以它永远不会终止.

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 命令,但作为 命令模块的 Ansible 文档 指出:

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:

给定的命令......不会通过shell处理

The given command ... will not be processed through the shell

因为 command 模块是直接执行命令而不是通过 shell,所以 shell 内置的像 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天全站免登陆