dictionaryansiblejinja2flattenansible-filter

Merge/Combine top level of dictionary


I am trying to create dictionary out of the servers stored in different env variables in ansible.

What i currently have is:

env_loadbalancer_vservers2: "{{ hostvars[inventory_hostname] | dict2items | selectattr('key', 'match', 'env_.*_loadbalancer_vservers(?![_.])') | list | items2dict }} "

Which will:

  1. get all variables in ansible for a specific host,
  2. change dict to items type
  3. as we can easily access now key value I will match only keys I want using regex
  4. Change it back to list
  5. Back to dict

problem is that output looks like this:

{
     "env_decision_manager_loadbalancer_vservers": {
         "decision_central": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 600,
         }
     },
     "env_ftp_loadbalancer_vservers": {
         "ftp_1": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "FTP",
             "ssl": false,
             "timeout": 9010,
         }
     },
     "env_jboss_loadbalancer_vservers": {
         "jboss": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 600,
         }
         "jboss_adm": {
             "ip_or_dns": "som_other_ip",
             "port": "rando_number",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 86410,
         }
     }

While my desired output should look like:

{
         "decision_central": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 600,
         },
         "ftp_1": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "FTP",
             "ssl": false,
             "timeout": 9010,
         },
         "jboss": {
             "ip_or_dns": "ip",
             "port": "port",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 600,
         },
         "jboss_adm": {
             "ip_or_dns": "som_other_ip",
             "port": "rando_number",
             "protocol": "SSL",
             "ssl": true,
             "timeout": 86410,
         }

So practically I need to remove "Top-level key tier" and merge their values. I've spent quite a time on this solution without any good progress and I would be happy for any advice :)

PS. The solution should be "clean" without any custom modules or actual tasks, the best idea would just add some functions to the filter pipeline mentioned above that will result in the correct format of dict

Thank you :)


Solution

  • Select the attribute value

      regexp: 'env_.*_loadbalancer_vservers(?![_.])'
      l1: "{{ hostvars[inventory_hostname]|
              dict2items|
              selectattr('key', 'match', regexp)|
              map(attribute='value')|
              list }}"
    

    gives the list

      l1:
      - decision_central:
          ip_or_dns: ip
          port: port
          protocol: SSL
          ssl: true
          timeout: 600
      - ftp_1: null
          ip_or_dns: IP
          port: port
          protocol: FTP
          ssl: false
          timeout: 9010
      - jboss:
          ip_or_dns: ip
          port: port
          protocol: SSL
          ssl: true
          timeout: 600
        jboss_adm:
          ip_or_dns: som_other_ip
          port: rando_number
          protocol: SSL
          ssl: true
          timeout: 86410
    

    Combine the items of the list

      d1: "{{ {}|combine(l1) }}"
    

    gives the dictionary you're looking for

      d1:
        decision_central:
          ip_or_dns: ip
          port: port
          protocol: SSL
          ssl: true
          timeout: 600
        ftp_1:
          ip_or_dns: ip
          port: port
          protocol: FTP
          ssl: false
          timeout: 9010
        jboss:
          ip_or_dns: ip
          port: port
          protocol: SSL
          ssl: true
          timeout: 600
        jboss_adm:
          ip_or_dns: som_other_ip
          port: rando_number
          protocol: SSL
          ssl: true
          timeout: 86410