Ansible for Network Engineers
Variables, Jinja2, and the template Module
What you'll learn
- That Ansible variables use the exact {{ }} Jinja2 syntax already learned
- How playbook vars:, group_vars, and host_vars supply values to a template
- How to use the template module to render the same vlan_config.j2 file from Phase 2.9
- That the underlying rendering behavior is identical — only the caller changed
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
You already know this syntax
Every Ansible playbook variable is written {{ variable_name }}. That is not Ansible's own invention — it's the exact Jinja2 expression syntax "Jinja2 Fundamentals Through Network Examples" (Configuration & Template Automation, Lesson 2) already taught.
- Python calls Template.render()directly, in a script you wrote
- {{ hostname }}, {{ vlan.id }}Jinja2 expressions
- Ansible's template module calls Jinja2 for you
- {{ hostname }}, {{ vlan.id }}the exact same syntax
Where playbook variables come from
Variables can be set directly in a play's vars: block, or in separate group_vars/host_vars files keyed by group or hostname:
vlans:
- { id: 10, name: USERS }
- { id: 20, name: VOICE }Any host in the 'switches' group automatically picks up this vlans variable — no need to repeat it in every playbook that uses it. This is the same list-of-dicts shape from Configuration & Template Automation Lesson 3, now living in an Ansible variables file instead of a Python dict.
The same template file, a new caller
Here is the exact vlan_config.j2 file from Configuration & Template Automation's capstone — unchanged, byte for byte:
{% for vlan in vlans %}
vlan {{ vlan.id }}
name {{ vlan.name }}
{% endfor %}Identical to the file used in Configuration & Template Automation Lesson 6. Nothing about the template itself changes — only what calls it does.
Ansible's template module renders a .j2 file exactly the way Environment(...).get_template(...).render(...) did in Lesson 5 of that module — just invoked declaratively, as a task, instead of a Python function call:
- name: Render VLAN configuration from a template
hosts: localhost
connection: local
gather_facts: false
vars:
vlans:
- { id: 10, name: USERS }
- { id: 20, name: VOICE }
tasks:
- name: Render vlan_config.j2 for this device
ansible.builtin.template:
src: templates/vlan_config.j2
dest: /tmp/SW1_vlans.cfgsrc points at the same .j2 file; dest is where the rendered result is written. hosts: localhost and connection: local mean this genuinely runs with no network device — a real, deterministic Option B example.
This rendering was directly verified — the CLI wrapper around it wasn't
The vlan_config.j2 file above, and the exact VLAN data used throughout this module, were re-run through the same Jinja2 environment (trim_blocks=True, lstrip_blocks=True) verified in Configuration & Template Automation — confirmed to produce byte-identical output for every device in the fleet. Ansible's own template module is documented to use these same Jinja2 semantics internally. Running this specific playbook through the real ansible-playbook command was not independently executed in this authoring environment (see Lesson 2) — but the rendering logic underneath it is the same logic already proven correct.
vlan 10
name USERS
vlan 20
name VOICEThis is the exact, directly-verified output for SW1's two required VLANs — identical to what Configuration & Template Automation's own script produced for the same device and the same template.
Key takeaways
- Ansible's {{ }} variable syntax is the exact Jinja2 already taught in Configuration & Template Automation — not a new templating language.
- Playbook variables come from a play's vars:, or from group_vars/host_vars files keyed by group or hostname.
- The template module renders a .j2 file exactly the way a Python script's Template.render() call already did — same file, same output, different caller.
- The rendering logic itself was directly re-verified against Configuration & Template Automation's own proven output; running it through the real ansible-playbook CLI was not independently executed in this authoring environment.
- Jinja2's silent-empty behavior for a missing variable (Configuration & Template Automation Lesson 5) applies here too — 'rendered successfully' still never means 'correct.'