Search code examples
ansiblejson-query

Ansible json_query different result in python3 vs python2


i bumped into an issue after migrated from python2 to python3. Seems that migration somehow changed the way how json query is being processed. Maybe anyone has a hint how to fix this

vars:
vmk_out: 
  host_vmk_info:
    hostname: 
      [
            {
                ipv4_address: "10.10.10.101",
                ipv4_subnet_mask: "255.255.255.0",
                stack: "defaultTcpipStack"
            },
            {
                ipv4_address: "10.10.20.101",
                ipv4_subnet_mask: "255.255.255.0",
                stack: "vmotion"
            }
        ]
tasks:
  - name: Extract list of IPs 
    set_fact:
      output: "{{ vmk_out.host_vmk_info.values() |json_query('[].ipv4_address') }}"

Above ran under Python2 with Ansible 2.9.1 returns list of IP addresses but running the same under Python3 returns the empty list


Solution

  • I did not take time to dig into the root of the problem, but there is clearly a difference in the return of the values() function between python 2.7 and 3.x.

    Here is what a direct debug or vmk_out.host_vmk_info.values() looks like from my tests:

    ansible 2.9.1 - python 3.6

    ok: [localhost] => {
        "msg": "dict_values([[{'ipv4_address': '10.10.10.101', 'ipv4_subnet_mask': '255.255.255.0', 'stack': 'defaultTcpipStack'}, {'ipv4_address': '10.10.20.101', 'ipv4_subnet_mask': '255.255.255.0', 'stack': 'vmotion'}]])"
    }
    

    ansible 2.9.1 - python 2.7

    ok: [localhost] => {
        "msg": [
            [
                {
                    "ipv4_address": "10.10.10.101", 
                    "ipv4_subnet_mask": "255.255.255.0", 
                    "stack": "defaultTcpipStack"
                }, 
                {
                    "ipv4_address": "10.10.20.101", 
                    "ipv4_subnet_mask": "255.255.255.0", 
                    "stack": "vmotion"
                }
            ]
        ]
    }
    
    

    You have 2 solutions to fix your current code and make it compatible with both versions.

    Solution 1: make sure the output of values() always produces a list:

    output: "{{ vmk_out.host_vmk_info.values() | list | json_query('[].ipv4_address') }}"
    

    Solution 2: stop using values() and directly map the existing hostname list

    output: "{{ vmk_out.host_vmk_info.hostname | json_query('[].ipv4_address') }}"