Home > Enterprise >  How to grab Json array element having dynamically changing position in Ansible
How to grab Json array element having dynamically changing position in Ansible

Time:03-16

Below is my json file where i have log array inside server array which is inside domain array.

[
  {
    "?xml": {
      "attributes": {
        "encoding": "UTF-8",
        "version": "1.0"
      }
    }
  },
  {
    "domain": [
      {
        "name": "mydom"
      },
      {
        "domain-version": "12.2.1.3.0"
      },
      {
        "server": [
          {
            "name": "AdminServer"
          },
          {
            "ssl": {
              "name": "AdminServer"
            }
          },
          {
            "listen-port": "12400"
          },
          {
            "listen-address": "mydom.host1.bank.com"
          }
        ]
      },
      {
        "server": [
          {
            "name": "myserv1"
          },
          {
            "ssl": [
              {
                "name": "myserv1"
              },
              {
                "login-timeout-millis": "25000"
              }
            ]
          },
          {
            "log": [
              {
                "name": "myserv1"
              },
              {
                "file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
              }
            ]
          }
        ]
      },
      {
        "server": [
          {
            "name": "myserv2"
          },
          {
            "ssl": {
              "name": "myserv2"
            }
          },
         {
           "reverse-dns-allowed": "false"
         },
          {
            "log": [
              {
                "name": "myserv2"
              },
              {
                "file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
              }
            ]
          }
        ]
      }
    ]
  }
]

The position of log array inside server array may change as shown in the json above.

I wish to grab the output as below:

myserv1_log: "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
myserv2_log: "/web/bea_logs/domains/mydom/myserv2/myserv2.log"

There are two challenges that i m facing.

  1. server may not always be the 3rd key of domain array.
  2. log array may not alway be a key for all server arrays and thus should not be printed. For example. server name AdminServer does not have any log list while myserv1 & myserv2 do have.

Also, log if present may not always be the 2nd key of server array as seen in the json.

A solution for when log is always the second element of server aarray was provided as below:

- hosts: localhost
  gather_facts: no
  vars:
    json: "{{ lookup('file', './file.json') | from_json }}"
  tasks:
    - name: display
      debug:
        msg: "name: {{ servername }} --> filename: {{ filename }}"
      loop: "{{ json[1].domain }}"
      vars:
        servername: "{{ item.server.0.name }}_log"
        filename: "{{ item['server'][2]['log'][1]['file-name'] }}"
      when: item.server is defined and item.server.2.log is defined

Kindly suggest.

CodePudding user response:

you have lot of solutions to do that, one :

- hosts: localhost
  gather_facts: no
  vars:
    json: "{{ lookup('file', './file.json') | from_json }}"
  tasks:
    - name: display
      debug:
        msg: "{{ server.0.name }} -> {{ filename.0.log[1]['file-name'] }}"
      loop: "{{ json[1].domain }}"
      vars:
        server: "{{ item.server | selectattr('name', 'defined') }}"
        filename:  "{{ item.server | selectattr('log', 'defined') }}"
      when: item.server is defined and (item.server | selectattr('log', 'defined')) != []

result:

skipping: [localhost] => (item={'name': 'mydom'}) 
skipping: [localhost] => (item={'domain-version': '12.2.1.3.0'}) 
skipping: [localhost] => (item={'server': [{'name': 'AdminServer'}, {'ssl': {'name': 'AdminServer'}}, {'listen-port': '12400'}, {'listen-address': 'mydom.host1.bank.com'}]}) 
ok: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': [{'name': 'myserv1'}, {'login-timeout-millis': '25000'}]}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]}) => {
    "msg": "myserv1 -> /web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
ok: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'reverse-dns-allowed': 'false'}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]}) => {
    "msg": "myserv2 -> /web/bea_logs/domains/mydom/myserv2/myserv2.log"
}

despite your problem, try this another solution:

- hosts: localhost
  gather_facts: no
  vars:
    json: "{{ lookup('file', './file.json') | from_json }}"
  tasks:
    - name: display
      set_fact:
        values: "{{ values | d([])   [v] }}"
      loop: "{{ json[1].domain }}"
      vars:
        v: >-
          {%- set dico = (item | dict2items).0.value -%}
          {%- set result = {} -%}
          {%- for i in dico -%}
          {%- for x in i if x in ["name", "log"] -%}
          {%- if result.update({x: i[x]}) -%}{% endif -%}
          {%- endfor -%}
          {%- endfor -%}
          {%- if 'log' in result %}{{ result }}{% endif -%}
      when: item.server is defined and v != ''
    
    - debug:
        msg: "{{ item.name }} -> {{ item.log[1]['file-name'] }}"
      loop: "{{ values }}"
  • Related