Extra spaces appearing in Ansible templates
Asked Answered
M

1

24

I am generating config files and I want them to be indented just so. I started with a Jinja2 template that rendered correctly when called from a simple python program. When I call it from ansible, I will get 2 extra spaces on all but the first line of the loop. Generating things like YAML and python has been a real pain. I have taken to putting a comment line as the first line of a for block to fix this...

Here is a really simple example of a YAML generator:

playbook call:

  - name: generate bgp vars file, put in includes directory
    local_action: template src={{ role_dir }}/templates/bgp_vars.j2 dest={{ incvar_dir }}/bgp_vars.yaml
    run_once: true

section of template:

dc_route_reflectors:
{% for dc in SH_dcs %}
# dc is "{{ dc }}"
  {{ dc }}:
  {% for host in groups[bgpgroupname] if dc == hostvars[host].MYDC %}
    - "{{ hostvars[host].MAIN_MYADDR }}"
  {% endfor %}
{% endfor %}

rendered output:

dc_route_reflectors:

# dc is "pnp"
  pnp:
      - "10.100.16.3"
      - "10.100.32.3"
  # dc is "sgs"
  sgs:
      - "10.8.0.3"
      - "10.8.16.3"
  # dc is "cst"
  cst:
      - "10.4.0.3"
      - "10.4.16.3"
  # dc is "dse"
  dse:
      - "10.200.0.3"
      - "10.200.16.3"

Notice how the dc is "pnp" comment is not indented as it is shown in the template, but sgs,cst and dse comments are indented by 2 spaces. All of the array lines of ip addresses are also indented. I have tried various versions of adding "-" to the "%" things as Jinja2 describes, but none have given consistent correct results.

Others must have seen this before. I'm running 2.2.1.0 on CentOS7.

Minneapolis answered 20/3, 2017 at 21:31 Comment(0)
C
44

For a start, you can just remove the spaces you explicitly added in front of your statements and keep indentation only for the data:

dc_route_reflectors:
{% for dc in SH_dcs %}
# dc is "{{ dc }}"
  {{ dc }}:
{% for host in groups[bgpgroupname] if dc == hostvars[host].MYDC %}
    - "{{ hostvars[host].MAIN_MYADDR }}"
{% endfor %}
{% endfor %}

If you want to keep indentation of the statements, you can set lstrip_blocks option to True (notice: the declaration must be in the first line of the template):

#jinja2:lstrip_blocks: True
dc_route_reflectors:
{% for dc in SH_dcs %}
# dc is "{{ dc }}"
  {{ dc }}:
  {% for host in groups[bgpgroupname] if dc == hostvars[host].MYDC %}
    - "{{ hostvars[host].MAIN_MYADDR }}"
  {% endfor %}
{% endfor %}

Read more about whitespace control in Jinja2.


Ansible runs Jinja2 with trim_blocks enabled and lstrip_blocks disabled.

All the spaces you typed into the template (outside of the statements and expressions) are thus considered a part of the output. No "extra spaces" are added.

Notice how the dc is "pnp" comment is not indented as it is shown in the template, but sgs, cst and dse comments are indented by 2 spaces.

These two spaces are included in your template in the 7th line (before {% endfor %}).

All of the array lines of ip addresses are also indented.

These spaces are defined in your template in the 5th line (in front of the {% for host).

Communion answered 20/3, 2017 at 22:9 Comment(5)
That was it. When I was running it within python it must have defaulted to the opposite.Thanks.Minneapolis
@Minneapolis Please have a look at the Help Center: do not add a comment on your question or on an answer to say "Thank you"..Communion
Thanks @Communion for the #jinja2:lstrip_blocks: True What I dont understand is why Jinja as a template would mess with spaces in the first place, seems to defeat the purpose of a templateGriqua
if case you need to specify multiple jinja2 config #jinja2: trim_blocks: True, lstrip_blocks: TrueMenswear
Thanks. #jinja2: lstrip_blocks: True makes a lot more sense for me, generating an Envoy YAML config from a Jinja2 template with Ansible. This has bothered me quite a bit today until I finally found this answer. Almost feel like starting a bounty just to be able to give you some more rep @Communion :)Ito

© 2022 - 2024 — McMap. All rights reserved.