Ansible:从字典中删除一个项目
Ansible : delete an item from a dictionary
我有一本包含键值的字典,很少有值是列表。我想从字典中的列表中删除一个项目。字典看起来像下面有嵌套项。
字典看起来像:
title: Some Title
metadata :
manifest-version: 1.0
key: value
installers:
- name: someName1
version: 1.0
- name: someName2
version: 2.0
- name: someName3
packages:
- fileName: fileName1
version: 1.1.1
- fileName: fileName2
version: 2.2.2
- name: service
type: install
packages:
- name: serviceName1
manifest: someManifest2
source: abcd.tgz
files:
- file1.tar
- file2.tar
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
- name: serviceName3
manifest: someManifest3
source: ijkl.tgz
files:
- file5.tar
- file6.tar
如何删除包含 name: serviceName3
的项目?
要么
如果没有以下项目,我可以将字典复制到另一个字典吗?
最终的字典不应包含以下项目:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
简单的解决方案
让我们创建一个应删除的词典列表
vars:
ritem:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
下面的任务可以完成工作
- set_fact:
inst2: "{{ installers|selectattr('packages', 'defined')|list }}"
- set_fact:
inst1: "{{ installers|difference(inst2) }}"
- set_fact:
inst4: "{{ inst4|default(inst1) + [
item|combine({'packages': item.packages|difference(ritem)})] }}"
loop: "{{ inst2 }}"
- debug:
var: inst4
给予
"inst4": [
{
"name": "someName1",
"version": 1.0
},
{
"name": "someName2",
"version": 2.0
},
{
"name": "someName3",
"packages": [
{
"fileName": "fileName1",
"version": "1.1.1"
},
{
"fileName": "fileName2",
"version": "2.2.2"
}
]
},
{
"name": "service",
"packages": [
{
"files": [
"file1.tar",
"file2.tar"
],
"manifest": "someManifest2",
"name": "serviceName1",
"source": "abcd.tgz"
},
{
"files": [
"file5.tar",
"file6.tar"
],
"manifest": "someManifest3",
"name": "serviceName3",
"source": "ijkl.tgz"
}
],
"type": "install"
}
]
字典格式
如果字典的格式(排序)不完全相同,那么简单的解决方案将不起作用。例如,如果文件的顺序不同,项目将不会被删除
vars:
ritem:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file4.tar
- file3.tar
这可以通过几个自定义过滤器来解决。让我们创建列表 rhash
以简化字典的比较并将其放入 vars
rhash: "{{ ritem|map('dict_flatten')|map('hash')|list }}"
下面的任务给出相同的结果
- set_fact:
inst3: "{{ inst3|default([]) + [
filter|
list_select_list_bool(item.packages, negative=True)|
list] }}"
vars:
filter: "{{ item.packages|
map('dict_flatten')|
map('hash')|
map('bool_in', rhash)|
list }}"
loop: "{{ inst2 }}"
- set_fact:
inst4: "{{ inst4|default(inst1) + [
item.0|combine({'packages': item.1})] }}"
loop: "{{ inst2|zip(inst3)|list }}"
- debug:
var: inst4
自定义过滤器
$ cat filter_plugins/filers.py
def bool_in(x, l):
return (x in l)
def dict_flatten(d, separator='.'):
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + separator)
elif type(x) is list:
i = 0
for a in sorted(x):
flatten(a, name + str(i) + separator)
i += 1
else:
out[name[:-1]] = x
flatten(d)
return out
def list_select_list_bool(b, l, negative=False):
l2=[]
for bi,li in zip(b,l):
if negative:
if not bi:
l2.append(li)
else:
if bi:
l2.append(li)
return l2
class FilterModule(object):
def filters(self):
return {
'bool_in': bool_in,
'dict_flatten': dict_flatten,
'list_select_list_bool': list_select_list_bool
}
我有一本包含键值的字典,很少有值是列表。我想从字典中的列表中删除一个项目。字典看起来像下面有嵌套项。
字典看起来像:
title: Some Title
metadata :
manifest-version: 1.0
key: value
installers:
- name: someName1
version: 1.0
- name: someName2
version: 2.0
- name: someName3
packages:
- fileName: fileName1
version: 1.1.1
- fileName: fileName2
version: 2.2.2
- name: service
type: install
packages:
- name: serviceName1
manifest: someManifest2
source: abcd.tgz
files:
- file1.tar
- file2.tar
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
- name: serviceName3
manifest: someManifest3
source: ijkl.tgz
files:
- file5.tar
- file6.tar
如何删除包含 name: serviceName3
的项目?
要么
如果没有以下项目,我可以将字典复制到另一个字典吗?
最终的字典不应包含以下项目:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
简单的解决方案
让我们创建一个应删除的词典列表
vars:
ritem:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file3.tar
- file4.tar
下面的任务可以完成工作
- set_fact:
inst2: "{{ installers|selectattr('packages', 'defined')|list }}"
- set_fact:
inst1: "{{ installers|difference(inst2) }}"
- set_fact:
inst4: "{{ inst4|default(inst1) + [
item|combine({'packages': item.packages|difference(ritem)})] }}"
loop: "{{ inst2 }}"
- debug:
var: inst4
给予
"inst4": [
{
"name": "someName1",
"version": 1.0
},
{
"name": "someName2",
"version": 2.0
},
{
"name": "someName3",
"packages": [
{
"fileName": "fileName1",
"version": "1.1.1"
},
{
"fileName": "fileName2",
"version": "2.2.2"
}
]
},
{
"name": "service",
"packages": [
{
"files": [
"file1.tar",
"file2.tar"
],
"manifest": "someManifest2",
"name": "serviceName1",
"source": "abcd.tgz"
},
{
"files": [
"file5.tar",
"file6.tar"
],
"manifest": "someManifest3",
"name": "serviceName3",
"source": "ijkl.tgz"
}
],
"type": "install"
}
]
字典格式
如果字典的格式(排序)不完全相同,那么简单的解决方案将不起作用。例如,如果文件的顺序不同,项目将不会被删除
vars:
ritem:
- name: serviceName2
manifest: someManifest2
source: efgh.tgz
files:
- file4.tar
- file3.tar
这可以通过几个自定义过滤器来解决。让我们创建列表 rhash
以简化字典的比较并将其放入 vars
rhash: "{{ ritem|map('dict_flatten')|map('hash')|list }}"
下面的任务给出相同的结果
- set_fact:
inst3: "{{ inst3|default([]) + [
filter|
list_select_list_bool(item.packages, negative=True)|
list] }}"
vars:
filter: "{{ item.packages|
map('dict_flatten')|
map('hash')|
map('bool_in', rhash)|
list }}"
loop: "{{ inst2 }}"
- set_fact:
inst4: "{{ inst4|default(inst1) + [
item.0|combine({'packages': item.1})] }}"
loop: "{{ inst2|zip(inst3)|list }}"
- debug:
var: inst4
自定义过滤器
$ cat filter_plugins/filers.py
def bool_in(x, l):
return (x in l)
def dict_flatten(d, separator='.'):
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + separator)
elif type(x) is list:
i = 0
for a in sorted(x):
flatten(a, name + str(i) + separator)
i += 1
else:
out[name[:-1]] = x
flatten(d)
return out
def list_select_list_bool(b, l, negative=False):
l2=[]
for bi,li in zip(b,l):
if negative:
if not bi:
l2.append(li)
else:
if bi:
l2.append(li)
return l2
class FilterModule(object):
def filters(self):
return {
'bool_in': bool_in,
'dict_flatten': dict_flatten,
'list_select_list_bool': list_select_list_bool
}