在ansible的路径中访问具有未知键的嵌套字典
Access a nested dict with unknown keys in the path in asnible
我遇到了一个问题,我还没有找到解决方案。
我从设备中收集了一些库存数据并得到了这样的数据:
{
"inventory_items": {
"main": {
"chassis": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Chassis",
"name": "Chassis",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
}
},
"non-chassis": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Route Processor",
"name": "module R0",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"GLC-SX-MMD": {
"descr": "GE SX",
"name": "subslot 0/0 transceiver 3",
"pid": "GLC-SX-MMD",
"sn": "123456789",
"vid": "V01 "
},
"SFP-10G-LR": {
"descr": "SFP+ 10GBASE-LR",
"name": "subslot 0/0 transceiver 1",
"pid": "SFP-10G-LR",
"sn": "123456789",
"vid": "V02 "
},
"SP7041-E-R": {
"descr": "GE T",
"name": "subslot 0/0 transceiver 7",
"pid": "SP7041-E-R",
"sn": "123456789",
"vid": "V02 "
},
"SPA-1X10GE-WL-V2": {
"descr": "1-port 10 Gigabit Ethernet Shared Port Adapter XFP based",
"name": "SPA subslot 0/1",
"pid": "SPA-1X10GE-WL-V2",
"sn": "123456789",
"vid": "V02 "
},
"XFP-10G-MM-SR": {
"descr": "10GBASE-SR/SW",
"name": "subslot 0/1 transceiver 0",
"pid": "XFP-10G-MM-SR",
"sn": "123456789",
"vid": "V03 "
}
}
},
"slot": {
"Power Supply Module 0": {
"other": {
"Power Supply Module 0": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 0",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
},
"Power Supply Module 1": {
"other": {
"Power Supply Module 1": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 1",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
}
}
}
}
我想遍历这些项目,但我对路径并不感兴趣,也无法预测。问题是在给定的示例中访问第一项将是
inventory_items['main']['chassis']
但是第二项是
inventory_items['main']['non-chassis']
其他项目是
inventory_items['slot']
如果每个项目的路径不同,我不知道如何遍历这些项目。我只对每个项目的字典感兴趣,而不是路径。但我不知道如何访问它们。
有没有办法只查找每个项目的 keys/value,但将它们作为每个项目的一个字典?
我想要得到的是一个可以像这样用“with_items”循环的列表
{
"inventory_items": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Chassis",
"name": "Chassis",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"ASR1001-X": {
"descr": "Cisco ASR1001-X Route Processor",
"name": "module R0",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"GLC-SX-MMD": {
"descr": "GE SX",
"name": "subslot 0/0 transceiver 3",
"pid": "GLC-SX-MMD",
"sn": "123456789",
"vid": "V01 "
},
"GLC-TE": {
"descr": "GE T",
"name": "subslot 0/0 transceiver 7",
"pid": "GLC-TE",
"sn": "123456789",
"vid": "V01 "
},
"Power Supply Module 0": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 0",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
},
"Power Supply Module 1": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 1",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
}
如果键不是唯一的,则创建一个列表。比如有两个key同名ASR1001-X
- set_fact:
iitems: "{{ iitems|d([]) + _keys|zip(_vals)|map('combine') }}"
loop: "{{ inventory_items.main.keys()|list }}"
vars:
_list: "{{ inventory_items.main[item]|dict2items }}"
_keys: "{{ _list|map(attribute='key')|
map('community.general.dict_kv', 'key') }}"
_vals: "{{ _list|map(attribute='value') }}"
- set_fact:
iitems: "{{ iitems|d([]) + _keys|zip(_vals)|map('combine') }}"
loop: "{{ inventory_items.slot.keys()|list }}"
vars:
_list: "{{ inventory_items.slot[item].other|dict2items }}"
_keys: "{{ _list|map(attribute='key')|
map('community.general.dict_kv', 'key') }}"
_vals: "{{ _list|map(attribute='value') }}"
给予
iitems|sort(attribute='key'):
- descr: Cisco ASR1001-X Chassis
key: ASR1001-X
name: Chassis
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
- descr: Cisco ASR1001-X Route Processor
key: ASR1001-X
name: module R0
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
- descr: GE SX
key: GLC-SX-MMD
name: subslot 0/0 transceiver 3
pid: GLC-SX-MMD
sn: '123456789'
vid: 'V01 '
- descr: Cisco ASR1001-X AC Power Supply
key: Power Supply Module 0
name: Power Supply Module 0
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
- descr: Cisco ASR1001-X AC Power Supply
key: Power Supply Module 1
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
- descr: SFP+ 10GBASE-LR
key: SFP-10G-LR
name: subslot 0/0 transceiver 1
pid: SFP-10G-LR
sn: '123456789'
vid: 'V02 '
- descr: GE T
key: SP7041-E-R
name: subslot 0/0 transceiver 7
pid: SP7041-E-R
sn: '123456789'
vid: 'V02 '
- descr: 1-port 10 Gigabit Ethernet Shared Port Adapter XFP based
key: SPA-1X10GE-WL-V2
name: SPA subslot 0/1
pid: SPA-1X10GE-WL-V2
sn: '123456789'
vid: 'V02 '
- descr: 10GBASE-SR/SW
key: XFP-10G-MM-SR
name: subslot 0/1 transceiver 0
pid: XFP-10G-MM-SR
sn: '123456789'
vid: 'V03 '
也可以创建字典,但相同的键会相互覆盖。例如,请注意下面的结果字典中只包含一个 ASR1001-X
- set_fact:
iitems: "{{ iitems|d({})|combine(inventory_items.main[item]) }}"
loop: "{{ inventory_items.main.keys()|list }}"
- set_fact:
iitems: "{{ iitems|d({})|combine(inventory_items.slot[item].other) }}"
loop: "{{ inventory_items.slot.keys()|list }}"
给予
iitems:
ASR1001-X:
descr: Cisco ASR1001-X Route Processor
name: module R0
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
GLC-SX-MMD:
descr: GE SX
name: subslot 0/0 transceiver 3
pid: GLC-SX-MMD
sn: '123456789'
vid: 'V01 '
Power Supply Module 0:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 0
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
Power Supply Module 1:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
SFP-10G-LR:
descr: SFP+ 10GBASE-LR
name: subslot 0/0 transceiver 1
pid: SFP-10G-LR
sn: '123456789'
vid: 'V02 '
SP7041-E-R:
descr: GE T
name: subslot 0/0 transceiver 7
pid: SP7041-E-R
sn: '123456789'
vid: 'V02 '
SPA-1X10GE-WL-V2:
descr: 1-port 10 Gigabit Ethernet Shared Port Adapter XFP based
name: SPA subslot 0/1
pid: SPA-1X10GE-WL-V2
sn: '123456789'
vid: 'V02 '
XFP-10G-MM-SR:
descr: 10GBASE-SR/SW
name: subslot 0/1 transceiver 0
pid: XFP-10G-MM-SR
sn: '123456789'
vid: 'V03 '
备注
-
必须安装集合Community.General才能使用上面的过滤器
所以you dont know exactly the structure of dictionary
,要使用通用程序,我建议您使用自定义过滤器。
在您的 playbook 文件夹中创建一个文件夹 filter_plugins 并创建一个文件 myfilter.py,其中包含一个名为自定义过滤器.
myfilter.py: 它搜索第一个不是字典的键,我捕获它的父键
#!/usr/bin/python
class FilterModule(object):
parent = ""
result=[]
def filters(self):
return {
'customfilter': self.customfilter
}
def loopping(self, obj):
for k in obj:
if type(obj[k]) is dict:
self.parent= k
self.loopping(obj[k])
else:
self.result.append({self.parent: obj})
break
return
def customfilter(self, obj):
for k in obj:
self.loopping(obj[k])
return self.result
使用它的剧本:
- name: "make this working"
hosts: localhost
vars:
inventory_items:
main:
chassis:
ASR1001-X:
descr: Cisco ASR1001-X Chassis
name: Chassis
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
:
:
Power Supply Module 1:
other:
Power Supply Module 1:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
tasks:
- name: Debug
set_fact:
inventory_items: "{{ inventory_items | customfilter }}"
- name: display
debug:
msg: "{{ inventory_items }}"
除了列表格式外,结果与您想要的相同
我遇到了一个问题,我还没有找到解决方案。 我从设备中收集了一些库存数据并得到了这样的数据:
{
"inventory_items": {
"main": {
"chassis": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Chassis",
"name": "Chassis",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
}
},
"non-chassis": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Route Processor",
"name": "module R0",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"GLC-SX-MMD": {
"descr": "GE SX",
"name": "subslot 0/0 transceiver 3",
"pid": "GLC-SX-MMD",
"sn": "123456789",
"vid": "V01 "
},
"SFP-10G-LR": {
"descr": "SFP+ 10GBASE-LR",
"name": "subslot 0/0 transceiver 1",
"pid": "SFP-10G-LR",
"sn": "123456789",
"vid": "V02 "
},
"SP7041-E-R": {
"descr": "GE T",
"name": "subslot 0/0 transceiver 7",
"pid": "SP7041-E-R",
"sn": "123456789",
"vid": "V02 "
},
"SPA-1X10GE-WL-V2": {
"descr": "1-port 10 Gigabit Ethernet Shared Port Adapter XFP based",
"name": "SPA subslot 0/1",
"pid": "SPA-1X10GE-WL-V2",
"sn": "123456789",
"vid": "V02 "
},
"XFP-10G-MM-SR": {
"descr": "10GBASE-SR/SW",
"name": "subslot 0/1 transceiver 0",
"pid": "XFP-10G-MM-SR",
"sn": "123456789",
"vid": "V03 "
}
}
},
"slot": {
"Power Supply Module 0": {
"other": {
"Power Supply Module 0": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 0",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
},
"Power Supply Module 1": {
"other": {
"Power Supply Module 1": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 1",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
}
}
}
}
我想遍历这些项目,但我对路径并不感兴趣,也无法预测。问题是在给定的示例中访问第一项将是
inventory_items['main']['chassis']
但是第二项是
inventory_items['main']['non-chassis']
其他项目是
inventory_items['slot']
如果每个项目的路径不同,我不知道如何遍历这些项目。我只对每个项目的字典感兴趣,而不是路径。但我不知道如何访问它们。 有没有办法只查找每个项目的 keys/value,但将它们作为每个项目的一个字典?
我想要得到的是一个可以像这样用“with_items”循环的列表
{
"inventory_items": {
"ASR1001-X": {
"descr": "Cisco ASR1001-X Chassis",
"name": "Chassis",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"ASR1001-X": {
"descr": "Cisco ASR1001-X Route Processor",
"name": "module R0",
"pid": "ASR1001-X",
"sn": "123456789",
"vid": "V02 "
},
"GLC-SX-MMD": {
"descr": "GE SX",
"name": "subslot 0/0 transceiver 3",
"pid": "GLC-SX-MMD",
"sn": "123456789",
"vid": "V01 "
},
"GLC-TE": {
"descr": "GE T",
"name": "subslot 0/0 transceiver 7",
"pid": "GLC-TE",
"sn": "123456789",
"vid": "V01 "
},
"Power Supply Module 0": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 0",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
},
"Power Supply Module 1": {
"descr": "Cisco ASR1001-X AC Power Supply",
"name": "Power Supply Module 1",
"pid": "ASR1001-X-PWR-AC",
"sn": "123456789",
"vid": "V01 "
}
}
}
如果键不是唯一的,则创建一个列表。比如有两个key同名ASR1001-X
- set_fact:
iitems: "{{ iitems|d([]) + _keys|zip(_vals)|map('combine') }}"
loop: "{{ inventory_items.main.keys()|list }}"
vars:
_list: "{{ inventory_items.main[item]|dict2items }}"
_keys: "{{ _list|map(attribute='key')|
map('community.general.dict_kv', 'key') }}"
_vals: "{{ _list|map(attribute='value') }}"
- set_fact:
iitems: "{{ iitems|d([]) + _keys|zip(_vals)|map('combine') }}"
loop: "{{ inventory_items.slot.keys()|list }}"
vars:
_list: "{{ inventory_items.slot[item].other|dict2items }}"
_keys: "{{ _list|map(attribute='key')|
map('community.general.dict_kv', 'key') }}"
_vals: "{{ _list|map(attribute='value') }}"
给予
iitems|sort(attribute='key'):
- descr: Cisco ASR1001-X Chassis
key: ASR1001-X
name: Chassis
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
- descr: Cisco ASR1001-X Route Processor
key: ASR1001-X
name: module R0
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
- descr: GE SX
key: GLC-SX-MMD
name: subslot 0/0 transceiver 3
pid: GLC-SX-MMD
sn: '123456789'
vid: 'V01 '
- descr: Cisco ASR1001-X AC Power Supply
key: Power Supply Module 0
name: Power Supply Module 0
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
- descr: Cisco ASR1001-X AC Power Supply
key: Power Supply Module 1
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
- descr: SFP+ 10GBASE-LR
key: SFP-10G-LR
name: subslot 0/0 transceiver 1
pid: SFP-10G-LR
sn: '123456789'
vid: 'V02 '
- descr: GE T
key: SP7041-E-R
name: subslot 0/0 transceiver 7
pid: SP7041-E-R
sn: '123456789'
vid: 'V02 '
- descr: 1-port 10 Gigabit Ethernet Shared Port Adapter XFP based
key: SPA-1X10GE-WL-V2
name: SPA subslot 0/1
pid: SPA-1X10GE-WL-V2
sn: '123456789'
vid: 'V02 '
- descr: 10GBASE-SR/SW
key: XFP-10G-MM-SR
name: subslot 0/1 transceiver 0
pid: XFP-10G-MM-SR
sn: '123456789'
vid: 'V03 '
也可以创建字典,但相同的键会相互覆盖。例如,请注意下面的结果字典中只包含一个 ASR1001-X
- set_fact:
iitems: "{{ iitems|d({})|combine(inventory_items.main[item]) }}"
loop: "{{ inventory_items.main.keys()|list }}"
- set_fact:
iitems: "{{ iitems|d({})|combine(inventory_items.slot[item].other) }}"
loop: "{{ inventory_items.slot.keys()|list }}"
给予
iitems:
ASR1001-X:
descr: Cisco ASR1001-X Route Processor
name: module R0
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
GLC-SX-MMD:
descr: GE SX
name: subslot 0/0 transceiver 3
pid: GLC-SX-MMD
sn: '123456789'
vid: 'V01 '
Power Supply Module 0:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 0
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
Power Supply Module 1:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
SFP-10G-LR:
descr: SFP+ 10GBASE-LR
name: subslot 0/0 transceiver 1
pid: SFP-10G-LR
sn: '123456789'
vid: 'V02 '
SP7041-E-R:
descr: GE T
name: subslot 0/0 transceiver 7
pid: SP7041-E-R
sn: '123456789'
vid: 'V02 '
SPA-1X10GE-WL-V2:
descr: 1-port 10 Gigabit Ethernet Shared Port Adapter XFP based
name: SPA subslot 0/1
pid: SPA-1X10GE-WL-V2
sn: '123456789'
vid: 'V02 '
XFP-10G-MM-SR:
descr: 10GBASE-SR/SW
name: subslot 0/1 transceiver 0
pid: XFP-10G-MM-SR
sn: '123456789'
vid: 'V03 '
备注
必须安装集合Community.General才能使用上面的过滤器
所以you dont know exactly the structure of dictionary
,要使用通用程序,我建议您使用自定义过滤器。
在您的 playbook 文件夹中创建一个文件夹 filter_plugins 并创建一个文件 myfilter.py,其中包含一个名为自定义过滤器.
myfilter.py: 它搜索第一个不是字典的键,我捕获它的父键
#!/usr/bin/python
class FilterModule(object):
parent = ""
result=[]
def filters(self):
return {
'customfilter': self.customfilter
}
def loopping(self, obj):
for k in obj:
if type(obj[k]) is dict:
self.parent= k
self.loopping(obj[k])
else:
self.result.append({self.parent: obj})
break
return
def customfilter(self, obj):
for k in obj:
self.loopping(obj[k])
return self.result
使用它的剧本:
- name: "make this working"
hosts: localhost
vars:
inventory_items:
main:
chassis:
ASR1001-X:
descr: Cisco ASR1001-X Chassis
name: Chassis
pid: ASR1001-X
sn: '123456789'
vid: 'V02 '
:
:
Power Supply Module 1:
other:
Power Supply Module 1:
descr: Cisco ASR1001-X AC Power Supply
name: Power Supply Module 1
pid: ASR1001-X-PWR-AC
sn: '123456789'
vid: 'V01 '
tasks:
- name: Debug
set_fact:
inventory_items: "{{ inventory_items | customfilter }}"
- name: display
debug:
msg: "{{ inventory_items }}"
除了列表格式外,结果与您想要的相同