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

Я хочу избежать изменения имени переменной, поэтому мне нужно, чтобы переменная была зарегистрирована в одной из двух последних задач, а не в обеих.

Как вообще пропустить последнее задание, включая регистрацию, если его условие не выполнено?

2 ответа

Множественные задачи, ветвящиеся с небольшими вариациями, раздражают при написании в Ansible, и они выполняются медленно из-за накладных расходов на задачу. Иногда это можно свернуть в один скрипт с переменными. Вот моя быстрая и грязная попытка с несколькими строками оболочки. Отказ от ответственности: я не проверял это с 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 писать ветвящийся поток не так удобно, как во многих языках программирования.


См. также: community.zabbix В коллекции есть community.zabbix.zabbix_agent роль с другим способом ведения дел. Установите пакет агента из репозитория программного обеспечения, а затем создайте шаблон файла конфигурации, в котором большинство возможных значений могут быть получены из переменных. Очень распространенные шаблоны для Ansible.

Лично я предпочитаю стиль установки пакетов программного обеспечения, которые должны быть там. Он может исправить отсутствующие агенты, и вам не придется выяснять, что находится на хосте.

Это типичный случай для нестандартных фактов . Создайте динамические факты о Zabbix, добавив исполняемый скрипт zabbix.fact в /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'

Попробуй это. Учитывая удаленные хосты test_11 и test_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: локальные факты ( collect_subset: local )

    • zabbix: факты, собранные zabbix.fact

    • 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)
Другие вопросы по тегам