Filtering a nested structure in Jinja2, regexp matches?

Hi,

I'd like to produce a template which lists disk device links. These
are the things you might find in /dev/disk/by-id/*, e.g.:

$ ls /dev/disk/by-id
ata-SomeVendor_AAAAAAAAAAAA-00005_BBBBBBBBBBBBBB
ata-ST4000LM016-1N2170_W801ZG92
ata-OtherVendor_SSD_OVCCCCCCCCCCCCCCCCCC
ata-OtherVendor_SSD_OVCCCCCCCCCCCCCCCCCC-part1
ata-OtherVendor_SSD_OVCDDDDDDDDDDDDDDDDD
ata-OtherVendor_SSD_OVCDDDDDDDDDDDDDDDDD-part1
dm-name-somevg-somelv
dm-uuid-LVM-0ysSbtTVMkvV21YB9629d3ey3fljIuPZDJSrQdwdIrPdXShmIRJxAexoxC3Of2OB
.
.
.
etc

These are available inside the "ansible_device_links" fact like this:

talisker | SUCCESS => {
    "ansible_facts": {
.
.
        "ansible_device_links": {
            "ids": {
                "dm-10": [
                    "dm-name-somevg-somelv",
                    "dm-uuid-LVM-A5XH2ZUDE0z4zFHu4s2IRtrcXgIsa6VDsZcUg5DaoduHYNfFKTvTqX2VKQ8zryj0"
                ],
                "sdb": [
                    "ata-SomeVendor_AAAAAAAAAAAA-00005_BBBBBBBBBBBBBB",
                    "wwn-0x5002538c405ccf9f"
                ],
                "sde": [
                    "ata-OtherVendor_SSD_OVCCCCCCCCCCCCCCCCCC",
                    "wwn-0x515d90417a000100"
                ],
                "sde1": [
                    "ata-OtherVendor_SSD_OVCCCCCCCCCCCCCCCCCC-part1",
                    "wwn-0x515d90417a000100-part1"
                ],
                "sdf": [
                    "ata-OtherVendor_SSD_OVCDDDDDDDDDDDDDDDDD",
                    "wwn-0x515d90417a000067"
                ],
                "sdf1": [
                    "ata-OtherVendor_SSD_OVCDDDDDDDDDDDDDDDDD-part1",
                    "wwn-0x515d90417a000067-part1"
                ],
                .
                .
            },
.
.
}

I'm only interested in devices that begin with "ata-" and I don't
want to consider partitions, so anything that ends with "-partX" is
also not of interest.

I came up with the following Jinja2 template which works:

{% for dev, ids in ansible_device_links.ids.iteritems() %}
{% if "ata-" in ids[0] and "-part" not in ids[0] %}{{ ids[0] }}{% endif %}
{% endfor %}

That gets me a simple list like:

ata-SomeVendor_AAAAAAAAAAAA-00005_BBBBBBBBBBBBBB
ata-OtherVendor_SSD_OVCCCCCCCCCCCCCCCCCC
ata-OtherVendor_SSD_OVCDDDDDDDDDDDDDDDDD

Which is what I want.

My questions are:

- Could this be done more elegantly with some sort of map and/or
  selectattr filter?

- Is there any way to do a regexp match? I am concerned that without
  anchoring the "ata-" at the start or including the digits of the
  "-partX" bits that these strings could one day occur elsewhere in
  the id and erroneously exclude devices.

Thanks,
Andy

For the regex you could do this

{% for dev, ids in ansible_device_links.ids.iteritems() if ids.0.startswith('ata-') and not ids.0 | regex_search('-part[0-9]+$') %}
{{ ids[0] }}
{% endfor %}

Hi Kai,

>- Is there any way to do a regexp match? I am concerned that without
> anchoring the "ata-" at the start or including the digits of the
> "-partX" bits that these strings could one day occur elsewhere in
> the id and erroneously exclude devices.

For the regex you could do this

{% for dev, ids in ansible_device_links.ids.iteritems() if
ids.0.startswith('ata-') and not ids.0 | regex_search('-part[0-9]+$') %}
{{ ids[0] }}
{% endfor %}

Thank you very much!

I'm new to Jinja2 and was basing what I could do with it on the
contents of http://jinja.pocoo.org/docs/2.10/templates/. This has no
matches for "regex" so I thought I couldn't do that, and I also
didn't realise that I could use a method of a string object like
"startswith".

I see now that I should have been looking in the Ansible
documentation for filters, i.e.:
http://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#regular-expression-filters

Cheers,
Andy