无法在 ansible play 中读取 json 数据

Unable to read json data in ansible play

我有以下 json 数据文件:

[
   {
      "?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.myserver1.mybank.com"
               }
            ]
         },
         {
            "server": [
               {
                  "name": "SERV01"
               },
               {
                  "log": [
                     {
                        "name": "SERV01"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/SERV01/SERV01.log"
                     }
                  ]
               },
               {
                  "listen-port": "12401"
               },

               {
                  "listen-address": "mydom.myserver1.mybank.com"
               },

               {
                  "server-start": [
                     {
                        "java-vendor": "Sun"
                     },
                     {
                        "java-home": "/web/bea/platform1221/jdk"
                     }
                  ]
               }
            ]
         },
         {
            "server": [
               {
                  "name": "SERV02"
               },
               {
                  "log": [
                     {
                        "name": "SERV02"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/SERV02/SERV02.log"
                     }
                  ]
               },
               {
                  "listen-port": "12401"
               },

               {
                  "listen-address": "mydom.myhost2.mybank.com"
               },
               {
                  "server-start": [

                     {
                        "java-home": "/web/bea/platform1221/jdk"
                     }                  ]
               }
            ]
         }

      ]
   }
]

我希望显示所有服务器名称及其各自的端口号。

下面是我尝试显示所有服务器名称的失败尝试

AdminServer
SERV01
SERV02

我的剧本:

tasks:

  - name: Read the JSON file content in a variable
    shell: "cat {{ playbook_dir }}/tmpfiles/{{ Latest_Build_Number }}/testme.json"
    register: result

  - name: Server Names
    set_fact:
      servernames:  "{{ jsondata | json_query(jmesquery) }}"
    vars:
      jmesquery: '*.domain.server[*].name'

  - name: Server Names and Ports
    set_fact:
      serverinfo:  "{{ jsondata | json_query(jmesquery) }}"
    vars:
      jmesquery: '*.server[*].[name, port]'


  - name: Print all server names
    debug:
      msg: "{{ item}}"
    with_items:
      - "{{ servernames }}"

我也尝试了以下方法:

      jmesquery: 'domain.server[*].name'

没有错误,但输出中也没有数据。输出如下:

TASK [Print all server names] *********************************************************************************
Monday 21 February 2022  03:07:47 -0600 (0:00:00.129)       0:00:03.590 *******
ok: [localhost] => (item=) => {
    "msg": ""
}

能否建议我如何获得所需的数据?

很多解决方案,一个 使用 jmespath,你可以试试这个:


  tasks:

    - name: Read the JSON file content in a variable
      shell: "cat testme.json"
      register: result

    - name: jsondata
      set_fact:
        jsondata:  "{{ result.stdout | from_json }}"
       

    - name: Server Names
      set_fact:
        servernames:  "{{ servernames | default([]) + [dict(name=item[0], port=item[1])] }}"
      loop: "{{ jsondata | json_query(jmesquery0) | zip(jsondata | json_query(jmesquery1)) | list }}"
      vars:
        jmesquery0: '[].domain[].server[].name'
        jmesquery1: '[].domain[].server[]."listen-port"'

    - name: debug result
      debug:
        msg: "{{ servernames }}"

结果:


ok: [localhost] => {
    "msg": [
        {
            "name": "AdminServer",
            "port": "12400"
        },
        {
            "name": "SERV01",
            "port": "12401"
        },
        {
            "name": "SERV02",
            "port": "12401"
        }
    ]
}

由于您的数据在列表中的性质,您将不得不求助于条件来摆脱空对象和单个项目列表,否则会污染您的数据:

  • [].domain[?server].server,获取具有 属性 server
  • 的对象
  • [?name].name | [0]获取名字
  • [?"listen-port"]."listen-port" | [0]获取端口

因此,对您的数据的有效 JMESPath 查询将是

[].domain[?server]
  .server[]
  .{
     name: [?name].name | [0], 
     port: [?"listen-port"]."listen-port" | [0]
  }

在 Ansible 中,使用单个 JMESPath 查询,假设文件在控制器上:

- debug:
    var: >-
      lookup(
        'file', 
        playbook_dir ~ '/tmpfiles/' ~ Latest_Build_Number ~ '/testme.json'
      )
      | from_json
      | json_query('
          [].domain[?server]
            .server[]
            .{
              name: [?name].name | [0], 
              port: [?"listen-port"]."listen-port" | [0]
            }
      ')
  vars: 
    Latest_Build_Number: 1

这会产生

TASK [debug] *************************************************************************
ok: [localhost] => 
  ? |-
    lookup(
      'file',
      playbook_dir ~ '/tmpfiles/' ~ Latest_Build_Number ~ '/testme.json'
    ) | from_json | json_query('
        [].domain[?server]
          .server[]
          .{
            name: [?name].name | [0],
            port: [?"listen-port"]."listen-port" | [0]
          }
    ')
  : - name: AdminServer
      port: '12400'
    - name: SERV01
      port: '12401'
    - name: SERV02
      port: '12401'

如果文件在节点上而不是在控制器上,那么,您可以先 slurp 文件或求助于 cat,就像您在应用相同的 JMESPath 查询之前所做的那样。