Learning bite
Variables and templates
Render a small configuration from explicit, validated inputs.
On this page
Keep the shape stable and vary the values
A variable stores a value the playbook can use. A template combines those values with fixed text to produce a file. Jinja expressions use {{ ... }} for substitution; filters transform values, and tests such as is integer check their characteristics. Ansible renders the template on the control side and transfers the resulting file to the target.
In ansible-practice, create templates/study.conf.j2:
environment={{ study_environment }}
port={{ study_port }}
Replace site.yml with this complete playbook so there is no ambiguity about indentation or retained handlers:
- name: Render a study configuration
hosts: study
gather_facts: true
vars:
study_environment: local
study_port: 8080
tasks:
- name: Check the fixture port
ansible.builtin.assert:
that:
- study_port is integer
- study_port >= 1024
- study_port <= 65535
- name: Render the study configuration
ansible.builtin.template:
src: study.conf.j2
dest: "{{ ansible_facts['user_dir'] }}/learnwithsk-marker.txt"
mode: '0600'
notify: Report marker change
handlers:
- name: Report marker change
ansible.builtin.debug:
msg: Marker content or metadata changed.
Run ansible-playbook -i inventory.ini site.yml --syntax-check, then apply with --limit study-vm. Read the marker through the same SSH target. Expected contents are environment=local and port=8080 on separate lines. This is a text fixture; no service begins listening on 8080.
Validate before rendering
The assertion checks type before range. A YAML value 8080 is an integer, whereas a quoted "8080" is a string. Silently converting every string can conceal a configuration error, so this exercise rejects it. Application-specific rules might require a narrower range or an approved set of values.
Try a scoped override using JSON to preserve the integer type:
ansible-playbook -i inventory.ini site.yml --limit study-vm -e '{"study_port":8081}'
Expect the port line to change and the handler to run. Run the same command again to check that it settles. Run without the override to restore 8080. An invalid override such as {"study_port":80} should fail at the assertion before installing a new file.
Know where a value comes from
Role defaults, inventory values, play variables, and extra variables can all supply data. Extra variables have very high precedence, so an old command-line override can hide the inventory value you think you are testing. Choose a clear convention and inspect the effective value privately when debugging. Host facts are observed data, while a registered result captures a previous task's return value; neither is automatically an appropriate permanent configuration default.
For JSON or YAML output, use a serializer or format-aware filter rather than hand-escaping arbitrary strings. A template that renders successfully may still be invalid for the application. The template module's validate option can invoke the application's real syntax checker against a temporary file before installation. Our two-line fixture has no application validator and makes no claim about NGINX or MicroBank readiness.
Checkpoint
If the task succeeds but the service rejects the file, which layer was missing? Validation of the target application's format and runtime behavior. If an integer assertion fails only with -e study_port=8081, inspect the supplied value's type; use the structured JSON form shown above.
Keep the template and complete playbook for the lab. Next, organize reusable configuration and preview changes while understanding how secrets and dry runs behave.
References: template module↗, variables and precedence↗, and filters↗.
Your notes and evidence
Record observations, questions, or links to your work. Keep credentials out of your notes.
Back up or restore this path
Progress and notes stay in this browser. A backup contains only this learning path.