Определение

В Ansible lookup плагины — это специфичные для Ansible расширения шаблонизатора Jinja2, которые используются для получения какой-либо информации на узле, который является контроллером (обычно это ваш ПК) Примеры lookup плагинов:

  • community.hashi_vault.vault_kv2_get — для получения значения ключа из Hashicorp Vault
  • ansible.builtin.file — для чтения файла
  • ansible.builtin.env — значение переменной окружения

Вот полный список lookup плагинов из ansible-galaxy

использование delegate_to не позволит выполнить lookup плагин на управляемом узле, его можно выполнить только на узле-контроллере

Приведу наипростейший пример, выведем содержимое переменной окружения $HOME на моем компьютере:

---
- hosts: localhost
  become: false
  gather_facts: false
  tasks:
    - name: Display $HOME
      ansible.builtin.debug:
        msg: "{{ lookup('env', 'HOME') }}"

Результат:

TASK [Display $HOME]
ok: [localhost] =>
  msg: /home/alexander

Интерполяция

Однако логика работы lookup отличается от привычной логики работы модулей, потому что их определение происходит в момент интерполяции:

---
- hosts: localhost
  become: false
  gather_facts: false
  vars:
    current_time: "{{ lookup('pipe','date +%H:%M:%S') }}"
  tasks:
    - name: Display time 1/2
      ansible.builtin.debug:
        msg: Current time {{ current_time }}

    - name: Pause for 3 seconds
      ansible.builtin.pause:
        seconds: 3

    - name: Display time 2/2
      ansible.builtin.debug:
        msg: Current time is {{ current_time }}

В примере выше может показаться, что обе таски выведут один и тот же результат, но как и я сказал — результат работы будет получен в момент интерполяции:

TASK [Display current time 1/2]
ok: [localhost] =>
  msg: Current time 21:21:44

TASK [Pause for 3 seconds]
Pausing for 3 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

TASK [Display current time 2/2]
ok: [localhost] =>
  msg: Current time is 21:21:47

until:

Еще один интересный пример работы вместе с директивой until: (напомню, что until: позволяет перезапускать модуль до получения нужного результата)

Предположим, что нам нужно сгенерировать UUID, который начинается с нуля и мы написали вот такой простой плей:

---
- hosts: localhost
  become: false
  gather_facts: false
  tasks:
    - name: Generate random UUID
      ansible.builtin.set_fact:
        random_uuid: "{{ lookup('pipe', 'uuidgen') }}"
      until: random_uuid.startswith('0')
      delay: 1
      retries: 20

С первого взгляда все выглядит правильно: мы получаем значение random_uuid из lookup плагина и далее проверяем не начинается ли он с нуля, но на самом деле значение random_uuid будет получено один раз при первой интерполяции плагина и дальше until: будет проверять одно и то же значение

Ansible UUID Wrong

Как обойти такое ограничение? Никак, совместить until:+lookup и “поймать” получившееся значение не получится, значение lookup генерируется один раз до выполнения самого модуля, правильнее всего в таком случае подобрать нужный плагин (или написать самому)

Можно добиться правильной работы условия until:+lookup подставив lookup плагин прямо в условие, но получить нужное значение все равно не получится, поскольку в модуле set_fact будет сохранено значение, которое он получил еще в момент вызова (см. пикрил)

---
- hosts: localhost
  become: false
  gather_facts: false
  tasks:
    - name: Generate random UUID
      vars:
        _random_uuid: "{{ lookup('pipe', 'uuidgen') }}"
      ansible.builtin.set_fact:
        random_uuid: "{{ _random_uuid }}"
      until: _random_uuid.startswith('0')
      delay: 1
      retries: 20

Ansible UUID OK