无法在ansible中理想地解析json文件

发布于 2025-01-13 22:46:05 字数 3573 浏览 4 评论 0原文

下面是我的示例 JSON 文件。

[
   {
      "?xml": {
         "attributes": {
            "encoding": "UTF-8",
            "version": "1.0"
         }
      }
   },
   {
      "domain": [

         {
            "server": [
               {
                  "name": "myserv1"
               },
               {
                  "ssl": {
                     "name": "myserv1"
                  }
               },
               {
                  "log": [
                     {
                        "name": "myserv1"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
                     }
                  ]
               }
            ]
         },
         {
            "server": [
               {
                  "name": "myserv2"
               },
               {
                  "ssl": {
                     "name": "myserv2"
                  }
               },
               {
                  "log": [
                     {
                        "name": "myserv2"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
                     }
                  ]
               }
            ]
         }
      ]
   }
]

我的要求是读取 json 文件并将值存储在如下文件中:

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

<server>_log: <file-name>

这是我的 Ansible 播放,它使用 JMESPath 查询来读取 json 数据。

- name: Server Names and log details
  set_fact:
    serverlog:  "{{ jsondata | json_query(jmesquery) }}"
  vars:
    jmesquery: '[].domain[].server[*].log[*].[name, "file-name"]'

- name: Print all server names with log details
  debug:
    msg: "{{ item }}"
  with_items:
    - "{{ serverlog }}"

正如你所看到的,我在输出中得到了几个 null

TASK [Print all server names with log details] *********************************
Wednesday 02 March 2022  03:17:45 -0600 (0:00:00.100)       0:00:04.730 *******
ok: [localhost] => (item=[]) => {
    "msg": []
}
ok: [localhost] => (item=[[['myserv1', None], [None, '/web/bea_logs/domains/mydom/myserv1/myserv1.log']]]) => {
    "msg": [
        [
            [
                "myserv1",
                null
            ],
            [
                null,
                "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
            ]
        ]
    ]
}

我使用下面的方法来摆脱 null ,但这也没有得到我想要的输出:

 - name: test
   set_fact:
     list2: "{{list2  + [item]}}"
   when: item != "null"
   with_items:
     - "{{serverlog}}"

 - name: Neww Print all server names with log details
   debug:
     msg: "{{ item }}"
   with_items:
     - "{{ list3 }}"

我还尝试了 StackOverflow 上提出的解决方案,但出现错误:

"{{ jsondata | selectattr('domain', 'defined') | map(attribute='domain') | flatten | map(attribute='server') | flatten | selectattr('log', 'defined') | map(attribute='log') | map('combine') }}"

输出错误:

The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'server'\n\nThe error appears to be in....

任何早期的类似帖子都没有得到任何有效的解决方案,这就是我决定在这里发布的原因:

从 ansible 列表中删除 null 元素

请建议。

Below is my sample JSON file.

[
   {
      "?xml": {
         "attributes": {
            "encoding": "UTF-8",
            "version": "1.0"
         }
      }
   },
   {
      "domain": [

         {
            "server": [
               {
                  "name": "myserv1"
               },
               {
                  "ssl": {
                     "name": "myserv1"
                  }
               },
               {
                  "log": [
                     {
                        "name": "myserv1"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
                     }
                  ]
               }
            ]
         },
         {
            "server": [
               {
                  "name": "myserv2"
               },
               {
                  "ssl": {
                     "name": "myserv2"
                  }
               },
               {
                  "log": [
                     {
                        "name": "myserv2"
                     },
                     {
                        "file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
                     }
                  ]
               }
            ]
         }
      ]
   }
]

My requirement is to read the json file and store the value in a file like below:

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

i.e

<server>_log: <file-name>

Here is my Ansible play that uses JMESPath query to read the json data.

- name: Server Names and log details
  set_fact:
    serverlog:  "{{ jsondata | json_query(jmesquery) }}"
  vars:
    jmesquery: '[].domain[].server[*].log[*].[name, "file-name"]'

- name: Print all server names with log details
  debug:
    msg: "{{ item }}"
  with_items:
    - "{{ serverlog }}"

As you can see I get several null values in the output

output:

TASK [Print all server names with log details] *********************************
Wednesday 02 March 2022  03:17:45 -0600 (0:00:00.100)       0:00:04.730 *******
ok: [localhost] => (item=[]) => {
    "msg": []
}
ok: [localhost] => (item=[[['myserv1', None], [None, '/web/bea_logs/domains/mydom/myserv1/myserv1.log']]]) => {
    "msg": [
        [
            [
                "myserv1",
                null
            ],
            [
                null,
                "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
            ]
        ]
    ]
}

I tied to get rid of the null using the below but that too does not get me the desired output:

 - name: test
   set_fact:
     list2: "{{list2  + [item]}}"
   when: item != "null"
   with_items:
     - "{{serverlog}}"

 - name: Neww Print all server names with log details
   debug:
     msg: "{{ item }}"
   with_items:
     - "{{ list3 }}"

I also tried the solution proposed on StackOverflow but I get error:

"{{ jsondata | selectattr('domain', 'defined') | map(attribute='domain') | flatten | map(attribute='server') | flatten | selectattr('log', 'defined') | map(attribute='log') | map('combine') }}"

Output error:

The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'server'\n\nThe error appears to be in....

Any earlier similar post did not get any working solution is why I decided to post here:

remove null elements from list ansible

Kindly suggest.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

筑梦 2025-01-20 22:46:05

你的json的结构总是相同的,不需要使用jmepath:

- 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'] }}"

结果:

ok: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': {'name': 'myserv1'}}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]}) => {
    "msg": "name: myserv1_log --> filename: /web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
ok: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]}) => {
    "msg": "name: myserv2_log --> filename: /web/bea_logs/domains/mydom/myserv2/myserv2.log"
}

一些解释:
json 是一个包含 2 条记录的数组,其中一个带有键 ?xml ,另一个带有键 domain

domain 是一个带有键 server 的数组code>

server 是一个包含不同键 name、ssl 和 log

log 的数组,包含不同键 name 和 file-名称


json[1].domain 只保留包含domain的部分,json[0]包含json的标头

item.server.0.name (= item['server'][0] ['name']) 是记录服务器的第一项,其中包含键 name

item['server'][2]['log'][1][ 'file-name'] 是记录服务器的第三项其中包含密钥log,日志的第二项包含密钥file-name

the structure of your json is always the same no need to use jmepath:

- 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'] }}"

result:

ok: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': {'name': 'myserv1'}}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]}) => {
    "msg": "name: myserv1_log --> filename: /web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
ok: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]}) => {
    "msg": "name: myserv2_log --> filename: /web/bea_logs/domains/mydom/myserv2/myserv2.log"
}

some explanations:
json is an array with 2 records one with key ?xml the other with key domain

domain is an array with key server

server is an array witk the differents keys name, ssl and log

log is an array with differents keys name and file-name


json[1].domain just keeps the part containing domain, json[0] contains the header of json

item.server.0.name (= item['server'][0]['name']) is the first item of record server which contains the key name

item['server'][2]['log'][1]['file-name'] is the third item for a record server which contains the key log and the second item of log contains the key file-name

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文