Ansible 变量在两个任务中注册,其中一个或另一个

Ansible 变量在两个任务中注册,其中一个或另一个

我有一个 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 的非常常见模式。

我个人更喜欢安装应该存在的软件包的方式。它可以修复丢失的代理,而您不必弄清楚主机上有什么。

相关内容