Ansible 剧本中的 'not to run multiple times' command/shell 如何执行任务
How 'not to run multiple times' command/shell task in Ansible playbook
我在 Ansible 中有一项任务是通过 RubyGems 选项安装 SASS 实用程序,它运行良好,没有任何问题。如果我再次重新 运行 同一个剧本,它会再次尝试重新安装此实用程序。
在这种情况下,如何在 Ansible 剧本中使用命令或 shell 用法 运行 一次。我已经通过使用 'when' 选项以某种方式处理了它而不是 运行 安装,但需要更好的指导 logic/implementation
任务信息:
- name: Install SASS packages by using npm utility.
command: /usr/bin/npm install -g sass
为了消除在 Ansible 剧本中重新 运行 执行上述命令任务,我使用了以下验证逻辑并添加了 'when' 选项,如下所示。这样可以吗,还是我们有更好的方法来处理这个问题?
- name: Validation of SASS packages availability.
shell: /usr/local/bin/sass --version
register: result
- debug:
msg: "{{ result.stdout }}"
- name: Install SASS packages by using npm utility.
command: /usr/bin/npm install -g sass
when: "'No such file or directory' in result.stdout"
结果:
TASK [mean-stack : Validation of SASS packages availability.] ************************************************************************************
changed: [linuxosdev003.local.lab]
TASK [mean-stack : debug] ************************************************************************************************************************
ok: [linuxosdev003.local.lab] => {
"msg": "1.47.0 compiled with dart2js 2.15.1"
}
TASK [mean-stack : Install SASS packages by using npm utility.] **********************************************************************************
skipping: [linuxosdev003.local.lab]
PLAY RECAP ***************************************************************************************************************************************
linuxosdev003.local.lab : ok=6 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
如果你想要一个幂等的剧本,你应该尽可能避免使用 command
或 shell
。特别是你的例子 - 删除 sass
并尝试你的剧本。它应该失败。检查文件是否存在
- name: "Check, if file exists"
stat:
path: "/usr/local/bin/sass"
register: sass_installed
但是 - 正如已经评论过的 - 使用 ansible 模块来安装 NPM 包,就像你对系统包所做的那样(package
或 yum
或 apt
)或 Python 模块(pip
)。该模块在最新的 RedHat release 2.9 中也可用 https://docs.ansible.com/ansible/2.9/modules/npm_module.html 并且应该很简单:
- name: "Install NPM package: sass"
npm:
name: "sass"
如果你需要安装多个 NPM 包,你可以遍历它们
- name: "Install NPM packages"
npm:
name: "{{ item }}"
loop:
- "package1"
- "package2"
正如@β.εηοιτ.βε 和@TRW 已经提到的,使用模块将消除此类检查的需要。
但是,如果只是检查路径是否存在那么简单,那么command module本身就可以这样使用:
- name: Install SASS packages by using npm utility.
command:
cmd: /usr/bin/npm install -g sass
creates: /usr/local/bin/sass
这等于您的 when
条件,即当 creates
中给定的路径不存在时,命令将 运行。
如果包管理器可用于任务,我更喜欢@β.εηοιτ.βε 和@TRW 的解决方案,有时可能需要留在 shell
模块上。对于这种情况,我使用与原始问题类似的方法。
---
- hosts: test.example.com
become: no
gather_facts: no
tasks:
- name: Gather installed Java version, if there is any
shell:
cmd: java -version 2>&1 | head -1 | cut -d '"' -f 2
register: result
check_mode: false
changed_when: false
failed_when: result.rc != 0 and result.rc != 127
- name: Set default version, if there is no
set_fact:
result:
stdout_lines: "0.0.0_000"
when: "'command not found' in result.stdout"
check_mode: false
- name: Report result
debug:
msg: "{{ result.stdout_lines }}"
check_mode: false
根据安装的版本,如有必要,将调用安装程序或更新程序来安装或更新到最新版本。
感谢
- Why does Java version go to
stderr
?
我在 Ansible 中有一项任务是通过 RubyGems 选项安装 SASS 实用程序,它运行良好,没有任何问题。如果我再次重新 运行 同一个剧本,它会再次尝试重新安装此实用程序。
在这种情况下,如何在 Ansible 剧本中使用命令或 shell 用法 运行 一次。我已经通过使用 'when' 选项以某种方式处理了它而不是 运行 安装,但需要更好的指导 logic/implementation
任务信息:
- name: Install SASS packages by using npm utility.
command: /usr/bin/npm install -g sass
为了消除在 Ansible 剧本中重新 运行 执行上述命令任务,我使用了以下验证逻辑并添加了 'when' 选项,如下所示。这样可以吗,还是我们有更好的方法来处理这个问题?
- name: Validation of SASS packages availability.
shell: /usr/local/bin/sass --version
register: result
- debug:
msg: "{{ result.stdout }}"
- name: Install SASS packages by using npm utility.
command: /usr/bin/npm install -g sass
when: "'No such file or directory' in result.stdout"
结果:
TASK [mean-stack : Validation of SASS packages availability.] ************************************************************************************
changed: [linuxosdev003.local.lab]
TASK [mean-stack : debug] ************************************************************************************************************************
ok: [linuxosdev003.local.lab] => {
"msg": "1.47.0 compiled with dart2js 2.15.1"
}
TASK [mean-stack : Install SASS packages by using npm utility.] **********************************************************************************
skipping: [linuxosdev003.local.lab]
PLAY RECAP ***************************************************************************************************************************************
linuxosdev003.local.lab : ok=6 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
如果你想要一个幂等的剧本,你应该尽可能避免使用 command
或 shell
。特别是你的例子 - 删除 sass
并尝试你的剧本。它应该失败。检查文件是否存在
- name: "Check, if file exists"
stat:
path: "/usr/local/bin/sass"
register: sass_installed
但是 - 正如已经评论过的 - 使用 ansible 模块来安装 NPM 包,就像你对系统包所做的那样(package
或 yum
或 apt
)或 Python 模块(pip
)。该模块在最新的 RedHat release 2.9 中也可用 https://docs.ansible.com/ansible/2.9/modules/npm_module.html 并且应该很简单:
- name: "Install NPM package: sass"
npm:
name: "sass"
如果你需要安装多个 NPM 包,你可以遍历它们
- name: "Install NPM packages"
npm:
name: "{{ item }}"
loop:
- "package1"
- "package2"
正如@β.εηοιτ.βε 和@TRW 已经提到的,使用模块将消除此类检查的需要。
但是,如果只是检查路径是否存在那么简单,那么command module本身就可以这样使用:
- name: Install SASS packages by using npm utility.
command:
cmd: /usr/bin/npm install -g sass
creates: /usr/local/bin/sass
这等于您的 when
条件,即当 creates
中给定的路径不存在时,命令将 运行。
如果包管理器可用于任务,我更喜欢@β.εηοιτ.βε 和@TRW 的解决方案,有时可能需要留在 shell
模块上。对于这种情况,我使用与原始问题类似的方法。
---
- hosts: test.example.com
become: no
gather_facts: no
tasks:
- name: Gather installed Java version, if there is any
shell:
cmd: java -version 2>&1 | head -1 | cut -d '"' -f 2
register: result
check_mode: false
changed_when: false
failed_when: result.rc != 0 and result.rc != 127
- name: Set default version, if there is no
set_fact:
result:
stdout_lines: "0.0.0_000"
when: "'command not found' in result.stdout"
check_mode: false
- name: Report result
debug:
msg: "{{ result.stdout_lines }}"
check_mode: false
根据安装的版本,如有必要,将调用安装程序或更新程序来安装或更新到最新版本。
感谢
- Why does Java version go to
stderr
?