Add dictionary as an item to an empty list

Viewed 92

I use Ansible to get some info from a firewall which returns the output as JSON. If the firewall has more than one package installed, it will return a list of dictionaries. If there is only a single package, it returns a dictionary. Let's say there is only one package installed so, it returns a dictionary - How do I add this dictionary as an item to a new list? So, the new list will only have a single element in it.

In a nutshell, how do I add a dictionary as an item to a new list?

The dictionary can be accessed here when a single package is installed.

(output.stdout | from_json).result.system.packages.entry

multiple packages

"packages": {
    "entry": [
        {
            "name": "package-1",
            "version": "1.1.0",
            "info": "installed"
        },
        {
            "name": "package-2",
            "version": "1.0.0",
            "info": "installed"
        }
    ]
}

single package

"packages": {
    "entry": {
        "name": "package-1",
        "version": "1.1.0",
        "info": "installed"
    }
}

EDIT

- name: "Set fact"
  set_fact:
    result: "{{ (output.stdout | from_json).result.system.packages.entry }}"

- name: "debug"
  debug:
    msg:
    - "{{ result | type_debug }}"
    - "{{ result }}"

!! RESULT !!    

"msg": [
        "dict",
        {
            "name": "package-1",
            "version": "1.1.0",
            "installed": "yes"
        }
    ]


- name: "Set fact"
  set_fact:
    result: []

- name: append dict to list
  set_fact:
    result = "{{ [(output.stdout | from_json).result.system.packages.entry] }}"

- name: "debug"
  debug:
    msg:
    - "{{ result | type_debug }}"
    - "{{ result }}"

!! RESULT !!    

"msg": [
        "list",
        []
    ] ```
2 Answers

You can define an empty list with the flow sequence in YAML:

packages: []

To add your element to that list, just feed this element in the list definition:

package: foo
packages: "{{ [package] }}"

Then for more than one, add a comma:

package1: foo
package2: foo
packages: "{{ [package1, package2] }}"

So, in your case:

packages: "{{ [(output.stdout | from_json).result.system.packages.entry] }}"

This said, as pointed by @Zeitounator, a better idea would possibly be to treat all cases the same and always enclose your result in a list.

This will indeed create a list of list when packages.entry is a list already, but that case can be handled by flattening the list of list with then flatten filter added to Jinja by Ansible.

So, you end up with:

packages: >-
  {{ 
    [
      (output.stdout | from_json).result
        .system
        .packages
        .entry
    ] 
    | flatten
  }}

Given the data

packages1:
  entry:
    - info: installed
      name: package-1
      version: 1.1.0
    - info: installed
      name: package-2
      version: 1.0.0

packages2:
  entry:
    info: installed
    name: package-1
    version: 1.1.0

Q: "How do I add a dictionary as an item to a new list?"

A: Always put the additional item to a list, even if it is already a list, and flatten the result. For example,

    - set_fact:
        result: "{{ result|d([]) + [item] }}"
      loop:
        - "{{ packages1.entry }}"
        - "{{ packages2.entry }}"
    - debug:
        var: result|flatten

gives

result|flatten:
  - info: installed
    name: package-1
    version: 1.1.0
  - info: installed
    name: package-2
    version: 1.0.0
  - info: installed
    name: package-1
    version: 1.1.0
Related