Ansible Lookup Plugins: Read Files, Passwords, URLs & More (Complete Guide)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
How to use Ansible lookup plugins to access external data. Read files, environment variables, passwords, URLs, CSV, DNS.
Ansible Lookup Plugins: Read Files, Passwords, URLs & More (Complete Guide)
Ansible lookup plugins fetch data from external sources during playbook execution — files, environment variables, password stores, URLs, DNS records, and more. They run on the control node (not remote hosts) and return data you can use in variables, templates, and tasks.
See also: 10 Proven Methods to Optimize Ansible Playbook Performance
Basic Syntax
# Jinja2 lookup function
"{{ lookup('plugin_name', 'argument') }}"
# With query (returns list)
"{{ query('plugin_name', 'argument') }}"
# With multiple arguments
"{{ lookup('plugin_name', 'arg1', 'arg2', key='value') }}"
Essential Lookup Plugins
file — Read Local Files
- name: Read a local file
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.file', '/etc/hostname') }}"
- name: Read SSH public key
ansible.builtin.authorized_key:
user: deploy
key: "{{ lookup('ansible.builtin.file', '~/.ssh/id_ed25519.pub') }}"
- name: Read multiple files
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.file', 'file1.txt', 'file2.txt') }}"
env — Read Environment Variables
- name: Get environment variable
ansible.builtin.debug:
msg: "Home directory is {{ lookup('ansible.builtin.env', 'HOME') }}"
- name: Use env var with default
vars:
db_host: "{{ lookup('ansible.builtin.env', 'DB_HOST') | default('localhost') }}"
ansible.builtin.debug:
msg: "Database: {{ db_host }}"
template — Render Jinja2 Templates
- name: Render a template string
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.template', 'templates/config.j2') }}"
password — Generate or Read Passwords
- name: Generate random password (saved to file)
vars:
db_password: "{{ lookup('ansible.builtin.password', '/tmp/dbpassword length=20 chars=ascii_letters,digits') }}"
ansible.builtin.debug:
msg: "Password: {{ db_password }}"
- name: Generate password without saving
vars:
temp_pass: "{{ lookup('ansible.builtin.password', '/dev/null length=16') }}"
ansible.builtin.debug:
msg: "{{ temp_pass }}"
pipe — Run Shell Commands
- name: Get output of a command
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.pipe', 'date +%Y-%m-%d') }}"
- name: Get git commit hash
vars:
git_hash: "{{ lookup('ansible.builtin.pipe', 'git rev-parse --short HEAD') }}"
ansible.builtin.debug:
msg: "Deploying commit {{ git_hash }}"
url — Fetch Data from URLs
- name: Get data from REST API
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.url', 'https://api.example.com/config', headers={'Authorization': 'Bearer ' + api_token}) }}"
- name: Read remote JSON
vars:
remote_config: "{{ lookup('ansible.builtin.url', 'https://config.example.com/app.json') | from_json }}"
ansible.builtin.debug:
msg: "Version: {{ remote_config.version }}"
csvfile — Read CSV Data
# data.csv:
# hostname,ip,role
# web01,10.0.0.1,webserver
# db01,10.0.0.2,database
- name: Look up IP from CSV
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.csvfile', 'web01 file=data.csv delimiter=, col=1') }}"
# Returns: 10.0.0.1
ini — Read INI Files
- name: Read value from INI file
ansible.builtin.debug:
msg: "{{ lookup('ansible.builtin.ini', 'port', section='database', file='config.ini') }}"
dict — Iterate Over Dictionaries
- name: Loop over dictionary
ansible.builtin.debug:
msg: "{{ item.key }}: {{ item.value }}"
loop: "{{ lookup('ansible.builtin.dict', my_dict) }}"
sequence — Generate Number Sequences
- name: Create users with sequence
ansible.builtin.user:
name: "user{{ item }}"
state: present
loop: "{{ query('ansible.builtin.sequence', 'start=1 end=5') }}"
lines — Read File Line by Line
- name: Process each line
ansible.builtin.debug:
msg: "Line: {{ item }}"
loop: "{{ lookup('ansible.builtin.lines', 'cat /etc/hosts') }}"
together / zip — Combine Lists
- name: Combine two lists
ansible.builtin.debug:
msg: "{{ item.0 }} → {{ item.1 }}"
loop: "{{ query('ansible.builtin.together', ['web', 'db', 'cache'], ['nginx', 'postgresql', 'redis']) }}"
first_found — Use First Existing File
- name: Include OS-specific vars
ansible.builtin.include_vars:
file: "{{ lookup('ansible.builtin.first_found', params) }}"
vars:
params:
files:
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
- default.yml
paths:
- vars/
See also: Maximize Ansible Efficiency with Callback Plugins for Resource Monitoring
lookup vs query
# lookup — returns comma-separated string (for backward compatibility)
"{{ lookup('ansible.builtin.file', 'a.txt', 'b.txt') }}"
# Returns: "contents_a,contents_b"
# query — always returns a list
"{{ query('ansible.builtin.file', 'a.txt', 'b.txt') }}"
# Returns: ["contents_a", "contents_b"]
Best practice: Use query() when looping, lookup() when you need a single value.
Error Handling
# Default: lookup fails if source is missing
# Use errors='ignore' or errors='warn'
- name: Graceful lookup
vars:
config: "{{ lookup('ansible.builtin.file', '/opt/config.yml', errors='ignore') | default('not found') }}"
ansible.builtin.debug:
msg: "Config: {{ config }}"
# With wantlist for safe iteration
- name: Safe list lookup
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ lookup('ansible.builtin.file', maybe_missing, errors='ignore', wantlist=True) | default([]) }}"
See also: Publishing Ansible Collections to Ansible Galaxy and Automation Hub
Custom Lookup Plugins
# plugins/lookup/my_lookup.py
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
results = []
for term in terms:
results.append(f"processed: {term}")
return results
- name: Use custom lookup
ansible.builtin.debug:
msg: "{{ lookup('my_lookup', 'test') }}"
FAQ
What are Ansible lookup plugins?
Lookup plugins fetch data from external sources (files, environment variables, URLs, databases) during playbook execution. They run on the control node and return data for use in variables, templates, and task parameters.
What is the difference between lookup and query in Ansible?
lookup() returns results as a comma-separated string for backward compatibility. query() always returns a list. Use query() when looping over results and lookup() when you need a single string value.
How do I read a file in Ansible?
Use lookup('ansible.builtin.file', '/path/to/file') to read a local file on the control node. For remote files, use the ansible.builtin.slurp module instead.
Can lookup plugins access remote hosts?
No. Lookup plugins run only on the Ansible control node. To read data from remote hosts, use modules like ansible.builtin.slurp, ansible.builtin.fetch, or ansible.builtin.command.
How do I handle errors in lookup plugins?
Pass errors='ignore' to suppress errors and return an empty string, or errors='warn' to log a warning. Combine with | default('fallback') for safe defaults.
Conclusion
Lookup plugins are essential for dynamic playbooks that pull data from files, environment variables, APIs, and other sources. Use FQCN (ansible.builtin.file) for clarity and query() when you need list results.
Related Articles
• Ansible Variables: Complete Guide • Ansible set_fact: Create Runtime Variables • Ansible Jinja2 Filters: Complete ReferenceCategory: troubleshooting