I recently had to use a Jinja2 if statement to create variables depending on a set of conditions in an Ansible role. To achieve this, I had to revisit YAML block scalars and Jinja2 whitespace control.
YAML block style scalar
A scalar in YAML represents an indivisible value such as a string, number, or boolean, as opposed to sequences (lists) or mappings (dictionaries).
You can represent a scalar in YAML using either flow or block style.
Flow style ignores indentations and is most suitable for short and simple structures.
Block style preserves indentations and makes large or complex data structures more human-readable.
---
flow_style_list: [foo,bar]
flow_style_dict: {foo: bar, bar: foo}
block_style_list:
- foo
- bar
block_style_dict:
foo: bar
bar: foo
A block style scalar can be folded (>
) or literal (|), both with or without chomping (>- or |-).
$ cat playbook.yml
---
- name: YAML block scalar examples.
hosts: localhost
tasks:
- name: Literal block scalar.
ansible.builtin.debug:
msg: |
I will
keep all
newlines.
- name: Literal block scalar with chomping.
ansible.builtin.debug:
msg: |-
I will
keep all
newlines, but strip the last newline.
- name: Folded block scalar.
ansible.builtin.debug:
msg: >
I will
replace newlines
with whitespaces.
- name: Folded block scalar with chomping.
ansible.builtin.debug:
msg: >-
I will
replace newlines
with whitespaces and also
strip the last newline.
$ ansible-playbook playbook.yml
PLAY [YAML block scalar examples.] ************************************************************
TASK [Literal block scalar.] ************************************************************
ok: [localhost] => {
"msg": "I will\nkeep all\nnewlines.\n"
}
TASK [Literal block scalar with chomping.] ************************************************************
ok: [localhost] => {
"msg": "I will\nkeep all\nnewlines, but strip the last newline."
}
TASK [Folded block scalar.] ************************************************************
ok: [localhost] => {
"msg": "I will replace newlines with whitespaces.\n"
}
TASK [Folded block scalar with chomping.] ************************************************************
ok: [localhost] => {
"msg": "I will replace newlines with whitespaces and also strip the last newline."
}
PLAY RECAP ************************************************************
localhost : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Jinja2 whitespace and newline control
Jinja2 lets you strip whitespaces before and after a block by adding a minus sign (-) to the start or end of a block tag.
{% for item in [1,2,3] %}
{{ item }}
{%- endfor %}
If we render the above template with the ansible.builtin.template module, we get:
1
2
3
By adding a minus sign (-) to the end of the first b
lock tag we can strip all leading whitespaces from the block:
{% for item in [1,2,3] -%}
{{ item }}
{%- endfor %}
1
2
3
Adding a minus sign (-) to the start of the last block tag will move all blocks to the same line:
{% for item in [1,2,3] %}
{{ item }}
{%- endfor %}
1 2 3
Finally, by adding a minus sign (-) to the end of the first block tag and the start of the last block tag, Jinja2 will strip leading whitespaces and move all blocks to the same line:
{% for item in [1,2,3] -%}
{{ item }}
{%- endfor %}
123
Putting it to use in Ansible
We can then use a folded block style scalar with chomping (>-) to define a condition-based variable, and use Jinja2 whitespace control to remove unwanted spaces and newlines from the variable in Ansible:
$ cat playbook.yml
---
- name: Conditional variable example.
hosts: localhost
vars:
conditional_variable: >-
{% if item is eq(1) -%}
a
{%- elif item is eq(2) -%}
b
{%- else -%}
c
{%- endif %}
tasks:
- name: Print the conditional variable.
ansible.builtin.debug:
msg: "{{ conditional_variable }}"
loop:
- 1
- 2
- 3
$ ansible-playbook playbook.yml
PLAY [Conditional variable example.] ************************************************************
TASK [Print the conditional variable.] ************************************************************
ok: [localhost] => (item=1) => {
"msg": "a"
}
ok: [localhost] => (item=2) => {
"msg": "b"
}
ok: [localhost] => (item=3) => {
"msg": "c"
}
PLAY RECAP ************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Leave a Reply