"Flattening" a list into dictionary key/value in ansible

Viewed 212

I have a yaml data set as follows:

  - order_number: 1
    name: 7zip
    unique_id: uid_1637333977
    parameters:
      - msi_file_name: 7z2104-x64.msi
      - msi_file_path: c:\users\zztest\7z2104-x64.msi
      - msi_file_directory: c:\users\zztest

I am trying to set a new fact with just "parameters," but not have it be a list, but a collection of dictionary key/values

e.g.

new_variable: {
  msi_file_name: 7z2104-x64.msi
  msi_file_path: c:\users\zztest\7z2104-x64.msi
  msi_file_directory: c:\users\zztest
}

How do I go about returning "parameters" as a defined dictionary with key/values versus a list of key/values?

2 Answers

Given the yaml data set

  yaml_data_set:
    - order_number: 1
      name: 7zip
      unique_id: uid_1637333977
      parameters:
        - msi_file_name: 7z2104-x64.msi
        - msi_file_path: c:\users\zztest\7z2104-x64.msi
        - msi_file_directory: c:\users\zztest

combine the parameters, e.g.

  new_variable: "{{ yaml_data_set|map(attribute='parameters')|flatten|combine }}"

gives

  new_variable:
    msi_file_directory: c:\users\zztest
    msi_file_name: 7z2104-x64.msi
    msi_file_path: c:\users\zztest\7z2104-x64.msi

There are (at least) two ways: a sequence of dict2items and items2dict filter, or a more traditional use of dict.update. Which one you prefer is mostly personal preference, and whether you're going to have to explain the pipeline wizardry to a future colleague

pipeline

  - name: use a jijna2 pipeline
    set_fact:
      new_variable: >-
        {{ parameters | map("dict2items") | flatten | items2dict  }}

That flatten is in there because each item in the parameters list is going to, itself, become a list of dicts, shaped like this:

    [
        [
            {
                "key": "msi_file_name",
                "value": "7z2104-x64.msi"
            }
        ],

but by applying "flatten" to it, we get the shape that items2dict is expecting:

    [
            {
                "key": "msi_file_name",
                "value": "7z2104-x64.msi"
            }
    ]

In the end, it yields what you requested:

ok: [localhost] => changed=false
  ansible_facts:
    new_variable:
      msi_file_directory: c:\users\zztest
      msi_file_name: 7z2104-x64.msi
      msi_file_path: c:\users\zztest\7z2104-x64.msi

use dict.update

  - name: use update
    set_fact:
      new_variable: >-
        {%- set results = {} -%}
        {%- for p_dict in parameters -%}
        {%-   set _ = results.update(p_dict) -%}
        {%- endfor -%}
        {{ results }}

yields the same:

ok: [localhost] => changed=false
  ansible_facts:
    new_variable:
      msi_file_directory: c:\users\zztest
      msi_file_name: 7z2104-x64.msi
      msi_file_path: c:\users\zztest\7z2104-x64.msi
Related