'Get name and version from a dictionary formatted facts

Below ansible tasks display pip packages in dictionary format.

- name: Ganther pip packages
  pip_package_info:
    clients: pip3
  register: pip_pkgs

And the output is:

{
  "packages": {
    pip3: {
      "xxx": [
        {
          name: "xxx"
          source: "pip3"
          version: "1.0.0"
        }
      ],
      "yyy": [
        {
          name: "yyy"
          source: "pip3"
          version: "2.0.0"
        }
      ]
    }
  }
}

I tried to loop through the registered variable, but, I am getting errors about undefined variable. How to get the name and version from the above dictionary?



Solution 1:[1]

You can use the values method of the Python dictionary in order to have something that you could loop on:

- debug:
    msg: "{{ item.name }} is in version {{ item.version }}"
  loop: "{{ pip_pkgs.packages.pip3.values() | flatten }}"

Alternatively, it can also be achieved with dict2items, but makes the loop syntax a little bit longer, since you then have to map the attribute you are interested in — here, the value:

- debug:
    msg: "{{ item.name }} is in version {{ item.version }}"
  loop: >-
    {{
      pip_pkgs.packages.pip3
      | dict2items
      | map(attribute='value')
      | flatten
    }}

If you want to create a dictionary, this would be the easiest:

- set_fact:
    pip_packages: >-
      {{
        dict(
          _pip_pkg | map(attribute='name')
          | zip(_pip_pkg | map(attribute='version'))
        )
      }}
  vars:
    _pip_pkg: "{{ pip_pkgs.packages.pip3.values() | flatten }}"

The dictionary would look like

pip_packages:
  ansible: 5.6.0
  ansible-compat: 2.0.2
  ansible-core: 2.12.4
  ansible-lint: 6.0.2

Given the two tasks:

- pip_package_info:
    clients: pip3
  register: pip_pkgs

- debug:
    msg: "{{ item.name }} is in version {{ item.version }}"
  loop: "{{ pip_pkgs.packages.pip3.values() | flatten }}"
  loop_control:
    label: "{{ item.name }}"

This gives:

ok: [localhost] => (item=ansible) => 
  msg: ansible is in version 5.6.0
ok: [localhost] => (item=ansible-compat) => 
  msg: ansible-compat is in version 2.0.2
ok: [localhost] => (item=ansible-core) => 
  msg: ansible-core is in version 2.12.5
ok: [localhost] => (item=ansible-lint) => 
  msg: ansible-lint is in version 6.0.2

... list goes on

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1