ansible

Filtering dictionaries based on the existence of a key within the sub dictionary


I am trying to filter the following data based on the existence of username within the sub dictionary.

An optimal solution would be, when I don't have to mention every single key e.g. agtsvcaccount, sqlsvcaccount, sapwd, because this should be generic within other schemas.

This is an example input with the variable input_parameters, this output is from an Ansible debug task.

ok: [localhost] => {
    "msg": {
        "ansible": {
            "limit": [
                "vm1234.vmdomain.com",
                "vm5678.vmdomain.com"
            ]
        },
        "mssql": {
            "edition": "standard",
            "language": "en",
            "setupconfig": {
                "action": "Install",
                "agtsvcaccount": {
                    "type": "System User",
                    "username": "SQL_Agt",
                    "vault": "credvault",
                    "visibility": false
                },
                "agtsvcstartuptype": "Automatic",
                "features": [
                    "SQLENGINE"
                ],
                "forcereboot": false,
                "instancename": "MSSQLINSTANCE",
                "npenabled": true,
                "sapwd": {
                    "type": "Database",
                    "username": "sa",
                    "vault": "credvault",
                    "visibility": false
                },
                "securitymode": "SQL",
                "sqlcollation": "SQL_Latin1_General_CP1_CI_AS",
                "sqlsvcaccount": {
                    "type": "System User",
                    "username": "SQL_Svc",
                    "vault": "credvault",
                    "visibility": false
                },
                "sqlsvcstartuptype": "Automatic",
                "sqlsysadminaccounts": [
                    "Administrator"
                ],
                "tcpenabled": true
            },
            "version": "2022"
        }
    }
}

Right now, I am using something like this, which is not generic/dynamic enough, and i don't want to use account_identifiers for other schematics, which are very similar.

- name: 'Process credentials'
  ansible.builtin.include_role:
    name: 'mycollection.generic'
    tasks_from: 'user/{{ item.value.vault }}.yml'
  loop: '{{ input_parameters.mssql.setupconfig | dict2items }}'
  when: 'item.key in account_identifiers'
  vars:
    account_identifiers: ['sapwd','sqlsvcaccount','agtsvcaccount','ftsvcaccount','rssvcaccount','assvcaccount','issvcaccount']

Any ideas how to accomplish this?
I tried getting an idea from the Ansible documentation, but I think I'm missing something.


Solution

  • You can use selectattr on the list of dictionaries created by your dict2items, in order to test if a property of those dictionaries is defined.

    So, your loop would ends up being:

    loop: >-
      {{ 
        input_parameters.mssql.setupconfig 
          | dict2items 
          | selectattr('value.username', 'defined') 
      }}
    

    With a simplified debug task, on your input data:

    - debug:
        msg: "Username: {{ item.value.username }}"
      loop_control:
        label: "{{ item.key }}"
      loop: >-
          {{
            input_parameters.mssql.setupconfig
              | dict2items
              | selectattr('value.username', 'defined')
          }}
    

    You would get:

    ok: [localhost] => (item=agtsvcaccount) => 
      msg: 'Username: SQL_Agt'
    ok: [localhost] => (item=sapwd) => 
      msg: 'Username: sa'
    ok: [localhost] => (item=sqlsvcaccount) => 
      msg: 'Username: SQL_Svc'