5

I have a source json document that looks like this:

# Source json
{
  "nics": {
    "vlan_internal": {
      "mac": "aa:aa:aa:aa:aa:aa"
    },
    "vlan_external": {
      "mac": "aa:aa:aa:aa:aa:bb"
    }
  }
}

Using ansible's json_query filter (which uses jmespath), I want to manipulate the json above so that the output json document looks like this:

# Desired output json
{
  "vlan_internal": "aa:aa:aa:aa:aa:aa",
  "vlan_external": "aa:aa:aa:aa:aa:ab"
}

It seems that I should be using a multiselect hash of some kind, but I can't find a good way to get the vlan names (which are hash keys in the source json doc, not hash values) into the output json doc.

I won't know the names of the vlans ahead of the time, so I can't hardcode vlan_internal or vlan_external into the jmespath expression.

The closest I've come is with this jmespath expression:

nics.{ vlans: keys(@), macs: *.mac }

Which results in an output json doc that was almost-useful:

{
  "vlans": [
    "vlan_internal",
    "vlan_external"
  ],
  "macs": [
    "aa:aa:aa:aa:aa:aa",
    "aa:aa:aa:aa:aa:bb"
  ]
}

This would have worked for me if it were guaranteed that the order of the list of vlan names and the order of the list of mac addresses was the same as that of the source json document. But the jmespath specification makes it very clear that the keys() function is not required to return results in any specific order. Since I need to pair up a vlan name with the correct mac address, this won't work for me.

Does someone know a way to accomplish this with jmespath?

loudsong
  • 121
  • 1
  • 6

2 Answers2

1

With only JMESPath you can use this query:

@.nics | {vlan_internal: @.vlan_internal | values(@)[0], vlan_external: @.vlan_external | values(@)[0]}

with this your source JSON you will get:

{
  "vlan_internal": "aa:aa:aa:aa:aa:aa",
  "vlan_external": "aa:aa:aa:aa:aa:bb"
}
bosskay972
  • 890
  • 1
  • 6
  • 27
0

First of all im not sure you should go through all that troble. If you are uncertain witch keys you are goin to get, than you probebly would iterate through your entire json, and so, you know your item key.

Nevertheless, if you just want to export a new json, I was unable to find a way to use native JMESPath to do so. instead I used an ansible with_dict loop as follow:

     - name: Create new nic_dict json
       set_fact:
          nic_dict: "{{ {item.key: item.value.mac} | combine(nic_dict | default({})) }}"
       with_dict: "{{ nics }}"

Now you can use the nic_dict that looks like this:

"nic_dict": {
    "vlan_external": "aa:aa:aa:aa:aa:bb",
    "vlan_internal": "aa:aa:aa:aa:aa:aa"
}
nadavbrkt
  • 87
  • 5