我有一个 Ansible 角色,负责操作一些 Zabbix 组件。此角色有以下一组任务来检查 Zabbix 代理类型(1 或 2)和版本。
- name: Check if Zabbix Agent 2 is installed
ansible.builtin.shell:
cmd: which zabbix_agent2
register: zabbix_agent2_installed
ignore_errors: yes
- name: Check if Zabbix Agent D is installed
ansible.builtin.shell:
cmd: which zabbix_agentd
when: not zabbix_agent2_installed.stdout
register: zabbix_agentd_installed
ignore_errors: yes
- name: Stop if there is no Agent installed
ansible.builtin.fail:
msg: |
Zabbix Agent is not installed.
when: not zabbix_agent2_installed.stdout and not zabbix_agentd_installed.stdout and zabbix_component == "agent"
- name: Fetch Zabbix Agent 2 version
ansible.builtin.shell:
cmd: zabbix_agent2 -V | grep "zabbix_agent" | cut -d' ' -f3
when: zabbix_agent2_installed.stdout
register: zabbix_agent_ver_old
failed_when: zabbix_agent_ver_old.stderr
- name: Fetch Zabbix Agent D version
ansible.builtin.shell:
cmd: zabbix_agentd -V | grep "zabbix_agent" | cut -d' ' -f4
when: not zabbix_agentd_installed.skipped
register: zabbix_agent_ver_old
failed_when: zabbix_agent_ver_old.stderr
当我运行 playbook 时,变量“zabbix_agentd_ver_old”在最后两个任务中注册了两次,名称相同。即使最后一个任务被跳过,该变量也会被注册为已跳过。
TASK [zabbix_ansible : Check if Zabbix Agent 2 is installed] *********************************************************************
changed: [zbxproxy]
TASK [zabbix_ansible : Check if Zabbix Agent D is installed] *********************************************************************
skipping: [zbxproxy]
TASK [zabbix_ansible : Stop if there is no Agent installed] **********************************************************************
skipping: [zbxproxy]
TASK [zabbix_ansible : Fetch Zabbix Agent 2 version] *****************************************************************************
changed: [zbxproxy]
TASK [zabbix_ansible : Fetch Zabbix Agent D version] *******************************************************************************
skipping: [zbxproxy]
TASK [zabbix_ansible : ansible.builtin.debug] ************************************************************************************
ok: [zbxproxy] =>
zabbix_agent_ver_old:
changed: false
skip_reason: Conditional result was False
skipped: true
我想避免更改变量名称,因此我需要在最后两个任务中的任一个中注册变量,而不是同时在两个任务中注册。
如果不满足条件,我该如何完全跳过最后一项任务(包括注册)?
答案1
这是典型案例定制事实.通过添加可执行脚本创建有关 Zabbix 的动态事实zabbix 事实信息到/etc/ansible/facts.d在远程主机上。
以下脚本测试列表中可执行文件的存在zabbix_agent_list并返回 JSON 字典ansible_custom_zabix_agent使用逗号分隔的现有项目
shell> cat zabbix.fact
#!/bin/sh
zabbix_agent_list="/usr/local/bin/zabbix_agentd \
/usr/local/bin/zabbix_agent2"
zabbix_agent=""
for a in $zabbix_agent_list; do
if [ -x $a ]; then
zabbix_agent="$zabbix_agent $a"
fi
done
zabbix_agent=`echo $zabbix_agent | tr ' ' ','`
echo '{"'ansible_custom_zabix_agent'"': '"'$zabbix_agent'"}'
将此脚本分发到您想要提供此自定义事实的远程主机
- hosts: all
tasks:
- file:
state: directory
dest: /etc/ansible/facts.d
- copy:
src: zabbix.fact
dest: /etc/ansible/facts.d
mode: '0755'
测试一下。给定远程主机测试_11和测试_13
shell> ssh admin@test_11 ls -1 /usr/local/bin/zabbix_agent2
/usr/local/bin/zabbix_agent2
shell> ssh admin@test_13 ls -1 /usr/local/bin/zabbix_agentd
/usr/local/bin/zabbix_agentd
以下游戏
- hosts: all
vars:
zabbix_agent: "{{ ansible_facts.ansible_local.zabbix.ansible_custom_zabix_agent|
default('')|
split(',')|
first }}"
tasks:
- setup:
gather_subset: local
- debug:
var: ansible_facts.ansible_local.zabbix.ansible_custom_zabix_agent
- debug:
var: zabbix_agent
给出(节选)
ok: [test_11] =>
zabbix_agent: /usr/local/bin/zabbix_agent2
ok: [test_13] =>
zabbix_agent: /usr/local/bin/zabbix_agentd
笔记:
默认情况下,事实将是每次游戏收集。在这种情况下,您不必运行该任务设置。
如果您禁用事实收集,或者想要刷新事实,请运行任务设置
通过限制本地事实来加快事实收集速度。设置
gather_subset: local
变量ansible_custom_zabix_agent将被添加到字典中ansible_facts.ansible_local.zabbix.ansible_custom_zabix_agent
ansible_local:本地事实(收集子集:本地)
zabbix:收集的事实zabbix 事实信息
ansible_custom_zabix_agent:以逗号分隔的代理列表
变量ansible_custom_zabix_agent在上面的剧本中,如果列表中有更多项目,则可能是以逗号分隔的项目列表zabbix_agent_list存在。在这种情况下,将字符串拆分为列表并取第一项。
您可以向脚本添加其他功能并返回其他事实。
可以使用任何其他语言(例如 Python)来编写脚本。
Python 脚本示例
shell> cat /etc/ansible/facts.d/apache.fact
#!/usr/bin/env python3
import shutil
import subprocess
import yaml
import json
def main():
name = 'httpd'
path = shutil.which(name)
if path:
result = subprocess.run([name, '-v'], capture_output=True, text=True)
version = yaml.safe_load(result.stdout)
else:
version = None
ansible_custom_facts = {
'path': path,
'version': version
}
print(json.dumps(ansible_custom_facts))
if __name__ == '__main__':
main()
例如,
ansible_facts.ansible_local:
apache:
path: /usr/local/sbin/httpd
version:
Server built: unknown
Server version: Apache/2.4.46 (FreeBSD)
答案2
在 Ansible 中编写多个任务分支以进行细微变化很烦人,而且由于任务开销,运行速度很慢。有时可以将其压缩为一个带有变量的脚本。这是我用几行 shell 进行的快速尝试。免责声明:我没有用 zabbix 测试过它,尽管一般概念并不难。
- name: Fetch Zabbix Agent version
register: zabbix_agent_ver_result
shell:
# Note use of YAML multiple line to embed script http://yaml-multiline.info/
# Although much longer should probably go in a separate file with and a script task
cmd: |
WHICHZAGENT=$(which zabbix_agent2 || which zabbix_agentd );
case $WHICHZAGENT in
*agent2 )
VERFIELD=3
;;
*agentd )
VERFIELD=4
;;
esac;
${WHICHZAGENT} --version | grep 'zabbix_agent' | cut -d' ' -f ${VERFIELD};
- name: zabbix agent ver short name
set_fact:
zabbix_agent_ver: "{{ zabbix_agent_ver_result.stdout }}"
- debug:
var: zabbix_agent_ver
register: 将覆盖已存在的同名(主机范围)变量。跳过的任务并非不返回任何内容,而是返回跳过的状态。这令人困惑,我建议所有注册的任务变量名称都是唯一的。
在 Ansible 任务中编写分支流程并不像在许多编程语言中那么好。
也可以看看:社区.zabbix集合有一个社区.zabbix.zabbix_agent以不同的方式执行任务。从软件存储库安装代理包,然后模板配置文件,其中大多数可能的值可以来自变量。Ansible 的非常常见模式。
我个人更喜欢安装应该存在的软件包的方式。它可以修复丢失的代理,而您不必弄清楚主机上有什么。