1

In Ansible I can loop through a list of dicts/lists and then use the loop vars in the Ansible task, but also in the template I call on.

I'm trying to do the same in Salt, but it seems like it's not possible. At least not in the way I'm used to.

I have the following in my Pillar.

routes:
  ens4f0np0:
    - address: 192.168.1.0
      netmask: 255.255.255.192
      gateway: 172.18.48.1
    - address: 172.16.2.0
      netmask: 255.255.255.224
      gateway: 172.18.48.1

I loop through it in my state file, using only the key, which is the interface name.

{% for interface in salt['pillar.get']('routes') %}
  file.managed:
    - name: /etc/sysconfig/network-scripts/route-{{ interface }}
    - user: root
    - group: root
    - mode: '0644'
    - source: salt://linux/network/files/routes.jinja
    - template: jinja
{% endfor %}

Then in the template I want to use the interface, but on the first line I already get an error, because that variable does not exist.

# {{ interface }}
{% for route in salt['pillar.get']('routes:interface') %}
ADDRESS{{ loop.index }}={{ route.address }}
NETMASK{{ loop.index }}={{ route.netmask }}
GATEWAY{{ loop.index }}={{ route.gateway }}
{% endfor %}

When I remove the first line, the template is created, but is empty. This is due to the fact that the lookup in the routes structure fails. When I put there routes:ens4f0np0, then it works fine.

But as you can see, I need the name ens4f0np0 for the state file to point to the right network-script file, and then in that file I need the interface name as the key to use the right list of variables.

Does anyone know how I can improve this? Or replicate what I usually do in Ansible?

AquaL1te
  • 13
  • 2

1 Answers1

0

You need to pass the context to the template. For example:

{% for interface, routes in pillar["routes"].items() %}
/etc/sysconfig/network-scripts/route-{{ interface }}:
  file.managed:
    - user: root
    - group: root
    - mode: '0644'
    - source: salt://linux/network/files/routes.jinja
    - template: jinja
    - context:
        interface: {{ interface }}
        routes: {{ routes | tojson }}
{% endfor %}
# {{ interface }}
{% for route in routes %}
ADDRESS{{ loop.index }}={{ route.address }}
NETMASK{{ loop.index }}={{ route.netmask }}
GATEWAY{{ loop.index }}={{ route.gateway }}
{% endfor %}

Note also that using pillar for storing generic data will lead to a performance bottleneck. If the data is not secret, then store it in the state tree instead.

OrangeDog
  • 569
  • 4
  • 20