无法使用 RedHat 上的 Ansible 2.10 版本从 JSON 文件获取数组元素

Unable to get array element from JSON file using Ansible 2.10 version on RedHat

下面是我的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.host1.bank.com"
          }
        ]
      },
      {
        "server": [
          {
            "name": "myserv1"
          },
          {
            "ssl": [
              {
                "name": "myserv1"
              },
              {
                "login-timeout-millis": "25000"
              }
            ]
          },
          {
            "listen-port": "22421"
          }
        ]
      },
      {
        "server": [
          {
            "name": "myserv2"
          },
          {
            "ssl": {
              "name": "myserv2"
            }
          },
          {
            "reverse-dns-allowed": "false"
          },
          {
            "log": [
              {
                "name": "myserv2"
              },
              {
                "file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
              }
            ]
          },
          {
            "listen-port": "12401"
          }
        ]
      }
    ]
  }
]

我希望打印 listen-port,同时记住 listen-port 元素在数组中的位置可能会发生变化。

我能够使用下面的播放在最新的 ansible 版本 2.12.2 上获取监听端口

 - name: display Listen Port
   debug:
     msg: "{{ myserver.0.name }} -> {{ cpath[0]['listen-port'] }}"
   loop: "{{ jsondata[1].domain }}"
   vars:
     myserver: "{{ item.server | selectattr('name', 'defined') | list }}"
     cpath:  "{{ item.server | selectattr('listen-port', 'defined') | list }}"
   when: item.server is defined and (item.server | selectattr('listen-port', 'defined') | list ) != []

但是,这个游戏在 redhat OS 上不起作用,其中 ansible 版本是最新的 2.10。

以下是我收到的错误:

TASK [create YML for server name with Listen port] ************************************************************
Wednesday 16 March 2022  08:41:06 -0500 (0:00:00.171)       0:00:05.917 *******
skipping: [localhost] => (item={'name': 'mydom'})
skipping: [localhost] => (item={'domain-version': '12.2.1.3.0'})
failed: [localhost] (item={'server': [{'name': 'AdminServer'}, {'ssl': {'name': 'AdminServer'}}, {'listen-port': '12400'}, {'listen-address': 'mydom.host1.bank.com'}]}) => {"ansible_loop_var": "item", "changed": true, "cmd": "echo AdminServer_httpport: 12400>>/web/aes/admin/playbooks/Migrator/wlsdatadump.yml", "delta": "0:00:00.006786", "end": "2022-03-16 08:41:07.175709", "item": {"server": [{"name": "AdminServer"}, {"ssl": {"name": "AdminServer"}}, {"listen-port": "12400"}, {"listen-address": "mydom.host1.bank.com"}]}, "msg": "non-zero return code", "rc": 1, "start": "2022-03-16 08:41:07.168923", "stderr": "/bin/sh: 12400: Bad file descriptor", "stderr_lines": ["/bin/sh: 12400: Bad file descriptor"], "stdout": "", "stdout_lines": []}
skipping: [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'}]}]})
skipping: [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'}]}]})

能否请您提出任何其他解决方案?

我建议您创建一个自定义过滤器以避免多重选择:

您在文件夹 filter_plugins 中创建一个文件 myfilter.py(与您的剧本相同级别),我已将插件命名为 customfilter:

#!/usr/bin/python
class FilterModule(object):
    def filters(self):
        return {
            'customfilter': self.customfilter
        }
 
    def customfilter(self, json):
        result = []
        
        for obj in json[1]['domain']:
            for server in obj:
                ob = {}
                if server == 'server':                 
                    for k in obj[server]:
                        for x in k:
                            ob.update({x: k[x]})
                    result.append(ob)
                              
        #print(result)
        
        return result

剧本:

- hosts: localhost
  gather_facts: no
  vars:
    json: "{{ lookup('file', './file.json') | from_json | customfilter }}"
  tasks:
    - name: display
      debug:
        msg: "server name: {{ server }} -> filename: {{ filename }} -> listenport: {{ listenport }}"
      loop: "{{ json }}"
      vars:
        server: "{{ item.name }}"
        filename:  "{{ item.log[1]['file-name'] | d('')}}"
        listenport: "{{ item['listen-port'] | d('') }}"

结果:

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

插件的作用是将每个记录服务器的所有词典归为一个词典,简化你要使用的数据。

[
  {
    "name": "AdminServer",
    "ssl": {
      "name": "AdminServer"
    },
    "listen-port": "12400",
    "listen-address": "mydom.host1.bank.com"
  },
  {
    "name": "myserv1",
    "ssl": [
      {
        "name": "myserv1"
      },
      {
        "login-timeout-millis": "25000"
      }
    ],
    "listen-port": "22421"
  },
  {
    "name": "myserv2",
    "ssl": {
      "name": "myserv2"
    },
    "reverse-dns-allowed": "false",
    "log": [
      {
        "name": "myserv2"
      },
      {
        "file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
      }
    ],
    "listen-port": "12401"
  }
]