无法使用 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"
}
]
下面是我的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"
}
]