Definition
In Ansible lookup plugins are Ansible-specific extensions to the Jinja2 templating engine that are used to get some information on the node that is the controller (usually your PC) Examples of lookup plugins:
community.hashi_vault.vault_kv2_get
— to get the value of a key from Hashicorp Vaultansible.builtin.file
— to read a fileansible.builtin.env
— the value of an environment variable
Here is the full list of lookup plugins from ansible-galaxy
using
delegate_to
will not allow the lookup plugin to be executed on a managed node, it can only be executed on a controller node
Let me give you a very simple example: let’s display the contents of the environment variable $HOME
on my computer:
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Display $HOME
ansible.builtin.debug:
msg: "{{ lookup('env', 'HOME') }}"
Result:
TASK [Display $HOME]
ok: [localhost] =>
msg: /home/alexander
Interpolation
However, the logic of lookup
differs from the usual logic of modules, because their definition occurs at the moment of interpolation:
---
- 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 }}
In the example above, it may seem that both tasks will output the same result, but as I said, the result of the work will be obtained at the moment of interpolation:
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:
Another interesting example of working together with the until:
directive (let me remind you that until:
allows you to restart the module until you get the desired result)
Let’s assume that we need to generate a UUID that starts with zero and we wrote a simple play like this:
---
- 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
At first glance, everything looks correct: we get the random_uuid
value from the lookup
plugin and then check if it starts with zero, but in fact the random_uuid
value will be obtained once during the first interpolation of the plugin and then until:
will check the same value
How to bypass this limitation? The is no way, you can’t combine until:
+lookup
and “catch” the resulting value, the lookup
value is generated once before the module itself is executed, the best thing to do in this case is to select the right plugin (or write it yourself)
You can achieve correct operation of the until:
+lookup
condition by substituting the lookup
plugin directly into the condition, but you still won’t be able to get the desired value, since the set_fact
module will store the value it received at the time of the call (see picril)
---
- 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