# Pragmatic approach to extract a value from my inventory data object

**URL:** <https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855>\
**Category:** Get Help\
**Tags:** jmespath, playbook\
**Created:** [December 11, 2023, 9:11pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855 "2023-12-11T21:11:23Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![crc31](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/crc31/32/1760_2.png) [@crc31](https://forum.ansible.com/u/crc31)\
**Post date:** [December 11, 2023, 9:11pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/1 "2023-12-11T21:11:23Z")

</div>

Hello everyone,

I have a fairly large inventory data structure from which I need to extract a value within a playbook. I’m wondering if this is possible with native Ansible, for example, by directly applying a filter plugin in the playbook or so…

Here is my data structure represented as YAML for illustration:

```auto
hostvars[inventory_hostname]:
  interfaces:
    - name: lo0
      ipaddr:
        - addr: 192.0.2.1
          family:
            label: IPv4

```

I need the IP address (here “192.0.2.1”) from the key “_addr_”.

Short summary of the above data structure:

- the list “_interfaces_” has an element with a dict
- this dict has a key of “_name_” that **must** be of the value “_lo0_”
- it has also a key “_ipaddr_” that contains a list
- this list contains a dictionary that has the key “_family_”
- that key is a dict that has a key “_label_” that **must** be of the value “_IPv4_.”

As far as I know I could write a custom filter plugin for this, but I would prefer to have it natively within the playbook for better portability and understanding by operational colleagues.

Any help much appreciated!

Thanks,  
Alex

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [December 11, 2023, 9:51pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/2 "2023-12-11T21:51:45Z")

</div>

I’d use [JMESPath](https://jmespath.org/) for this via the [community.general.json\_query filter](https://docs.ansible.com/ansible/latest/collections/community/general/json_query_filter.html) see [Selecting JSON data: JSON queries](https://docs.ansible.com/ansible/latest/collections/community/general/docsite/filter_guide_selecting_json_data.html), the [JMESPath Terminal](https://github.com/jmespath-community/jmespath.terminal) makes working out queries a little easier.

This isn’t the answer but something like this should be possible work out:

```auto
"hostvars[inventory_hostname]".interfaces[?name=='lo0'].ipaddr|[].addr|[0]

```

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [December 11, 2023, 10:23pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/3 "2023-12-11T22:23:18Z")

</div>

`{{ hostvars[inventory_hostname].interfaces }}` is the same as `{{ interfaces }}`.  
With that simplification, the expression you want is… complicated. Here it is, built up one step at a time.

```yaml
    - name: interfaces
      ansible.builtin.debug:
        msg: '{{ interfaces }}'

    - name: interfaces.name==lo0
      ansible.builtin.debug:
        msg: '{{ interfaces
                 | selectattr("name","eq","lo0") }}'

    - name: interfaces.name==lo0 ipaddr
      ansible.builtin.debug:
        msg: '{{ interfaces
                 | selectattr("name","eq","lo0")
                 | map(attribute="ipaddr") }}'

    - name: interfaces.name==lo0 ipaddr flatten
      ansible.builtin.debug:
        msg: '{{ interfaces
                 | selectattr("name","eq","lo0")
                 | map(attribute="ipaddr")
                 | flatten }}'

    - name: interfaces.name==lo0 ipaddr flatten family.label==IPv4
      ansible.builtin.debug:
        msg: '{{ interfaces
                 | selectattr("name","eq","lo0")
                 | map(attribute="ipaddr")
                 | flatten
                 | selectattr("family.label", "eq", "IPv4") }}'

    - name: interfaces.name==lo0 ipaddr flatten family.label==IPv4 addr
      ansible.builtin.debug:
        msg: '{{ interfaces
                 | selectattr("name","eq","lo0")
                 | map(attribute="ipaddr")
                 | flatten
                 | selectattr("family.label", "eq", "IPv4")
                 | map(attribute="addr") }}'

```

Cheers!

---

<div class="post-metadata">

**Author:** ![crc31](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/crc31/32/1760_2.png) [@crc31](https://forum.ansible.com/u/crc31)\
**Post date:** [December 14, 2023, 3:38pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/4 "2023-12-14T15:38:05Z")

</div>

Thanks a lot for the great solutions. I’d prefer Todd’s ‘native’ solution if it didn’t require so many individual steps. I’ve installed JMESPath and got it to work with the following task and expression:

```auto
tasks:
  - name: Setting routerid to value of ipv4 loopback address
    ansible.builtin.set_fact:
      routerid: "{{ interfaces | community.general.json_query('[?name == `lo0`].ipaddr[] | [?family.label == `IPv4`].addr') }}"

```

I think I need to ponder a bit more about this really efficient looking expression… 🙂

A big thanks to both of you!

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [December 14, 2023, 4:28pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/5 "2023-12-14T16:28:38Z")

</div>

> [@crc31](#):
>
> I’d prefer Todd’s ‘native’ solution if it didn’t require so many individual steps.

If by steps you mean the five filters in the pipeline, that’s the nature of the beast.

But if by steps you mean playbook tasks, all but the last one are there just so you can see what each stage in the pipeline produces. It’s the expression in the last `debug` step that solves your initial ask.

My problem with a `json_query` solution is, now you have to grok both Jinja2 _and_ JMESPath queries.

---

<div class="post-metadata">

**Author:** ![crc31](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/crc31/32/1760_2.png) [@crc31](https://forum.ansible.com/u/crc31)\
**Post date:** [December 14, 2023, 9:42pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/6 "2023-12-14T21:42:05Z")

</div>

Oh, mea culpa, what nonsense I’ve written. I’ve got a lot on my plate, sorry Todd. I believe the native solution, in its expression, is on par with the JSON query, obviously!

Now I’m torn because this decision will likely set the direction for hundreds of similar requests.

I wonder which implementation is more efficiently handled in software and executed in hardware. Perhaps I should conduct some performance tests between them.

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [December 14, 2023, 10:10pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/7 "2023-12-14T22:10:53Z")

</div>

> [@crc31](#):
>
> I wonder which implementation is more efficiently handled in software and executed in hardware. Perhaps I should conduct some performance tests between them.

Compared to all the things that have to work – on the controller and any remote hosts – for any playbook of any significance at all, you could optimize either of those expressions down to a single cycle and not notice any improvement.

Far more important is the number of seconds/minutes you and those who follow will have to spend looking at however you end up spelling the solution to this and other problems.

(1) Readability, (2) Maintainability, … (17) vi-vs.-emacs, … (276) Efficiency of Jinja2 expressions.

Okay, maybe I exaggerated. But in 100,000,000 runs you’ll not gain back the time it’s taken you to read this message.

OTOH, familiarity with JMESPath is certainly worthwhile, and Jinja2 is expressly “limited as a feature”. (I’ve never bought the “not designed to program with” argument, from Jinja2, Ansible, or elsewhere. It’s trotted out whenever someone pushes a tool beyond what the inventors envisioned. It’s the same as Apple’s old argument that color wasn’t important — until they released a color Mac. Hm.)

---

<div class="post-metadata">

**Author:** ![rndmh3ro](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/rndmh3ro/32/269_2.png) [@rndmh3ro](https://forum.ansible.com/u/rndmh3ro)\
**Post date:** [December 18, 2023, 4:09pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/8 "2023-12-18T16:09:13Z")

</div>

In terms of readabilty in the playbook, I’d use Chris’ solution, but define a second variable in the host\_vars:

`lo0_ipv4_address: "hostvars[inventory_hostname]".interfaces[?name=='lo0'].ipaddr|[].addr|[0]` (something like this, I’m in mobile so cannot test).

This would make the playbook more readable with the caveat that you have another layer of abstraction.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [January 17, 2024, 4:09pm UTC](https://forum.ansible.com/t/pragmatic-approach-to-extract-a-value-from-my-inventory-data-object/2855/9 "2024-01-17T16:09:59Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
