Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Jinja to filter by nested dictionary values

I have the following YAML in my SaltStack Pillar:

prometheus:
  services:
    cassandra:
      enabled: False
    cockroachdb:
      enabled: True
    haproxy:
      enabled: True
    swift:
      enabled: False

I want to be able to loop over a list of enabled services.

{% for enabled_service_name in prometheus.services | selectattr('enabled') %}
{{ enabled_service_name }}
{% endfor %}

However, this doesn't work because the attribute I'm trying to filter on is in a nested dictionary below the service name:

{'cassandra': {'enabled': False},
 'cockroachdb': {'enabled': True},
 'haproxy': {'enabled': True},
 'swift': {'enabled': False}}

I can obviously achieve what I want by applying a conditional test inside the loop:

{% for name, properties in prometheus.services | dictsort %}
{% if properties.enabled %}
configuration for {{ name }}
{% endif %}
{% endfor %}

However, I will be looping over this list often and would prefer to have Jinja apply the filter in-line in the for loop.

Is there a way to filter by the value of an item in the nested dictionary?

like image 816
corywright Avatar asked Oct 26 '25 08:10

corywright


2 Answers

Well, I think the better structured the yaml file in this case the more options you have to resolve the issue.

I would suggest the below restructure:

prometheus:
  services:
    - name: cassandra
      enabled: False
    - name: cockroachdb
      enabled: True
    - name: haproxy
      enabled: True
    - name: swift
      enabled: False

Then you can iterate in different ways, this might be one way:
{{ prometheus.services | selectattr('enabled', True) | map(attribute='name') | list }}

I hope this helps!

like image 82
Waheed Avatar answered Oct 29 '25 03:10

Waheed


Without changing the structure of your pillar, you can divide your list into two groups via groupby.

{% for group in prometheus.services.items() | groupby ('1.enabled') %}
{% if group.grouper = True %}
{% set enabled_services = group.list %}
{% else %}
{% set disabled_services = group.list %}
{% endif %}
{% endfor %}

It looks a bit more complicated, but it's useful if you need to loop through both lists.

like image 33
laocius Avatar answered Oct 29 '25 02:10

laocius