Ansible loop и register: как проверять результат каждой итерации

Задача Ansible проверяет несколько файлов в цикле. Результат сохранён в register, но следующая задача обращается к result.stdout и получает ошибку отсутствующего поля. С циклом одна задача даёт несколько отдельных результатов. Внешний объект содержит их список, а не один общий stdout.

Полезно сначала определить, какое решение нужно принять по каждому элементу. Возьмём безопасную проверку файлов конфигурации: для каждого заданного пути требуется узнать, существует ли обычный файл. Модуль stat возвращает соответствующие поля, поэтому не нужно запускать shell и разбирать ls.

Сохраним результаты вместе с исходным путём

- name: Check configuration paths
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    config_paths:
      - /etc/hosts
      - /tmp/example-required-config.yaml
  tasks:
    - name: Inspect each path
      ansible.builtin.stat:
        path: "{{ item }}"
      loop: "{{ config_paths }}"
      register: config_checks

    - name: Require an ordinary existing file
      ansible.builtin.assert:
        that:
          - check.stat.exists
          - check.stat.isreg | default(false)
        fail_msg: "Required file unavailable: {{ check.item }}"
      loop: "{{ config_checks.results }}"
      loop_control:
        loop_var: check
        label: "{{ check.item }}"

Playbook рассчитан на POSIX-controller. /etc/hosts обычно существует, а второй путь выбран как тестовый: заранее убедитесь, что его нет, если хотите увидеть отрицательный сценарий. При отсутствии второго файла assert завершит проверку неуспехом и покажет исходный путь. Создавать или удалять рабочие конфигурации для этого опыта не нужно.

Каждый элемент config_checks.results содержит результат stat и исходный item. Во втором цикле переменная названа check, чтобы не смешивать результат проверки с первоначальным именем item. Поле check.item сохраняет связь с путём без предположений о порядке строк stdout.

Прочитаем структуру по смыслу модуля

Stat не обязан возвращать stdout: его полезные данные находятся в stat. У command основным полем может быть rc, stdout и stderr. Поэтому перенос выражения из другого модуля без проверки структуры часто создаёт ошибку даже при правильном обходе results.

Для отсутствующего файла stat.exists равен false, а часть остальных полей может не существовать. В примере isreg защищён default(false), чтобы отсутствие поля тоже трактовалось как неисполнение требования. Проверка exists и isreg нужна, потому что существующий каталог по тому же пути ещё не является конфигурационным файлом.

Если тип объекта неважен, требование можно упростить до exists. Если важны владелец, режим или checksum, добавьте ровно эти условия и объясните, какое решение следует из их нарушения. Не превращайте дамп всех полей stat в самостоятельную проверку качества конфигурации.

Различим отрицательный результат и сбой задачи

Отсутствие файла — нормальный ответ stat, а недоступность узла или ошибка самого модуля — другой исход. Обычно неуспешная задача прерывает дальнейшую работу для host. Если вы намеренно продолжаете после ошибки, следующий этап должен явно различать failed, skipped и валидный результат; наличие списка results не гарантирует одинаковую форму всех элементов.

Условный when в первом цикле может пропустить часть элементов. Тогда нельзя безусловно читать у каждого stat или rc. Сначала выберите элементы, которые реально выполнились, либо обработайте skipped отдельной веткой. Пропуск обязательной проверки не должен молча становиться успехом.

Используем результаты без потери идентичности

Если после проверки требуется обработать только подходящие пути, переносите check.item или другой исходный ключ вместе с результатом. Отдельный список булевых значений без пути неудобен для диагностики: по нему трудно понять, какой объект нужно исправить. loop_control.label улучшает читаемость вывода, но не меняет содержимое результата.

На учебном наборе проверьте существующий файл, отсутствующий путь и существующий каталог. Эти три случая подтверждают смысл assert лучше, чем три одинаковых положительных примера. Затем перенесите тот же подход на пакетные операции: сначала получите структурированные результаты, затем примите явное решение по каждой исходной сущности.

Ещё по теме

Продолжить изучение

Хотите собрать настройку серверов в повторяемый процесс? Inventory, роли, шаблоны и обновление сервисов входят в программу «Ansible: автоматизация инфраструктуры».

Продолжить на практике

  • Ansible: автоматизация инфраструктуры ↗

    Настраивайте серверы воспроизводимо: inventory, playbooks, роли, шаблоны и секреты. Соберите автоматизацию для нескольких окружений, проверьте повторный запуск и обновляйте сервисы управляемо.