是否可以使用 Jinja/Ansible 映射多个属性?
Is it possible to map multiple attributes using Jinja/Ansible?
我想构建一个显示变量的键和值的输出。
以下完美运行...
# Format in Ansible
msg="{{ php_command_result.results | map(attribute='item') | join(', ') }}"
# Output
{'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}, {'value': {'svn_tag': '20150702r1_6.36_homeland'}, 'key': 'api'}
我想要的是同时显示 key
和 svn_tag
:
我可以显示 key
或 svn_tag
,但无法将它们放在一起。
msg="{{ php_command_result.results | map(attribute='item.key') | join(', ') }}"
# Output
ui, api
不过,这就是我想要的。
# Desired Output
api - 20150702r1_6.36_homeland
ui - 20150703r1_6.36_homeland
您可以使用以下技巧来完成:
创建 filter_plugin
。在 ansible.cfg 中添加 filter_plugins = <path to the folder>
。然后创建一个文件说 my_plugin.py
:
class FilterModule(object):
''' Custom filter '''
def filters(self, my_arg):
return <parse it here......>
示例:
playbook.yml
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- set_fact:
php_command_result:
results: {'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}
- debug: msg="Hey look what I got '{{ php_command_result.results | a }}'"
my_plugin.py
import json
class FilterModule(object):
def filters(self):
return {'a': a}
def a(a):
r = '%s - %s' % (a['key'], a['value']['svn_tag'])
return r
快速简便的方法:只需使用 python/php/shell
或您喜欢的 shell
模块。像这样:
- name: Pars output
shell: python -c "import json; json.loads('{{ php_command_result.results }}') ....
这是没有自定义 filter_plugin 或 运行 shell 命令的解决方案。但是,它需要在 with_items 循环中设置额外的事实(php_fmt)。
- hosts: localhost
connection: local
gather_facts: false
tasks:
- set_fact:
php_command_result:
results: '[{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]'
- set_fact:
php_fmt: "{{ php_fmt|default([])|union([item.key+' -- '+item.value.svn_tag ]) }}"
with_items: "{{ php_command_result.results }}"
- debug:
msg: "{{php_fmt|join(',')}}"
- set_fact:
php_command_result:
results: [{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]
- debug:
msg: "{% for result in php_command_result.results %}\
{{ result.key }} - {{ result.value.svn_tag }} |
{% endfor %}"
输出:
ok: [localhost] => {
"msg": "ui - 20150703r1_6.36_homeland | api - 20150702r1_6.36_homeland | "
}
如果您希望结果在不同的行上:
- debug:
msg: "{% set output = [] %}\
{% for result in php_command_result.results %}\
{{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}\
{% endfor %}\
{{ output }}"
输出:
ok: [localhost] => {
"msg": [
"ui - 20150703r1_6.36_homeland",
"api - 20150702r1_6.36_homeland"
]
}
如果需要,可以将其中任何一个放在一行上:
- debug:
msg: "{% for result in php_command_result.results %}{{ result.key }} - {{ result.value.svn_tag }} | {% endfor %}"
- debug:
msg: "{% set output = [] %}{% for result in php_command_result.results %}{{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}{% endfor %}{{ output }}"
这是另一个使用 filter_plugins
的答案,我发现它非常容易使用。
如果有人仍然需要这个你可以使用下面的代码(输入playbooks/filter_plugins/mapattributes.py):
#!/usr/bin/env python
class FilterModule(object):
def filters(self):
return { 'mapattributes': self.mapattributes }
def mapattributes(self, list_of_dicts, list_of_keys):
l = []
for di in list_of_dicts:
newdi = { }
for key in list_of_keys:
# newdi[key] = di[key]
if di.get(key, None) != None:
newdi[key] = di[key]
l.append(newdi)
return l
假设你有这个列表,你只需要输入来自:
INTERFACES:
- { name: GigabitEthernet1/0/24 , enabled: yes, state: up , description: FRONT }
- { name: GigabitEthernet1/0/9 , enabled: yes, state: up , description: BACK }
让我们创建另一个变量过滤只需要 key:values
test: "{{ INTERFACES | mapattributes(['name', 'description']) }}"
测试输出
- debug:
var: test
ok: [R1] => {
"test": [
{
"description": "FRONT",
"name": "GigabitEthernet1/0/24"
},
{
"description": "BACK",
"name": "GigabitEthernet1/0/9"
}
]
}
这让我有一个大字典,只切分我需要传递给 ios_interface/aggregate
的键
感谢 Nee6ione,我在 pallets/jinja github issue
上找到了它
我在搜索处理类似任务的方法时发现了这个问题,但我希望输出是另一个包含各个元素的 JSON 列表。我在 map
、filter
甚至 Jinja2 for
循环上花了很多时间,所以我也会 post 在这里回答。只需创建以下文件并通过 ansible-playbook
:
运行
- hosts: localhost
connection: local
vars:
to_test: [ {'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}, {'value': {'svn_tag': '20150702r1_6.36_homeland'}, 'key': 'api'} ]
tasks:
- debug:
msg: "to_test: {{ to_test }}"
- debug:
msg: "to_test reduced: {{ to_test | json_query('[].{key: key, svn_tag: value.svn_tag}') | list }}"
- debug:
msg: "to_test reduced: {{ to_test | json_query(query1) | list }}"
vars:
query1: "[].{key: key, svn_tag: value.svn_tag}"
最终结果是一个不错的 JSON 数组:
[{'key': 'ui', 'svn_tag': '20150703r1_6.36_homeland'}, {'key': 'api', 'svn_tag': '20150702r1_6.36_homeland'}]"
我想构建一个显示变量的键和值的输出。
以下完美运行...
# Format in Ansible
msg="{{ php_command_result.results | map(attribute='item') | join(', ') }}"
# Output
{'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}, {'value': {'svn_tag': '20150702r1_6.36_homeland'}, 'key': 'api'}
我想要的是同时显示 key
和 svn_tag
:
我可以显示 key
或 svn_tag
,但无法将它们放在一起。
msg="{{ php_command_result.results | map(attribute='item.key') | join(', ') }}"
# Output
ui, api
不过,这就是我想要的。
# Desired Output
api - 20150702r1_6.36_homeland
ui - 20150703r1_6.36_homeland
您可以使用以下技巧来完成:
创建
filter_plugin
。在 ansible.cfg 中添加filter_plugins = <path to the folder>
。然后创建一个文件说my_plugin.py
:class FilterModule(object): ''' Custom filter ''' def filters(self, my_arg): return <parse it here......>
示例:
playbook.yml
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- set_fact:
php_command_result:
results: {'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}
- debug: msg="Hey look what I got '{{ php_command_result.results | a }}'"
my_plugin.py
import json
class FilterModule(object):
def filters(self):
return {'a': a}
def a(a):
r = '%s - %s' % (a['key'], a['value']['svn_tag'])
return r
快速简便的方法:只需使用
python/php/shell
或您喜欢的shell
模块。像这样:- name: Pars output shell: python -c "import json; json.loads('{{ php_command_result.results }}') ....
这是没有自定义 filter_plugin 或 运行 shell 命令的解决方案。但是,它需要在 with_items 循环中设置额外的事实(php_fmt)。
- hosts: localhost
connection: local
gather_facts: false
tasks:
- set_fact:
php_command_result:
results: '[{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]'
- set_fact:
php_fmt: "{{ php_fmt|default([])|union([item.key+' -- '+item.value.svn_tag ]) }}"
with_items: "{{ php_command_result.results }}"
- debug:
msg: "{{php_fmt|join(',')}}"
- set_fact:
php_command_result:
results: [{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]
- debug:
msg: "{% for result in php_command_result.results %}\
{{ result.key }} - {{ result.value.svn_tag }} |
{% endfor %}"
输出:
ok: [localhost] => {
"msg": "ui - 20150703r1_6.36_homeland | api - 20150702r1_6.36_homeland | "
}
如果您希望结果在不同的行上:
- debug:
msg: "{% set output = [] %}\
{% for result in php_command_result.results %}\
{{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}\
{% endfor %}\
{{ output }}"
输出:
ok: [localhost] => {
"msg": [
"ui - 20150703r1_6.36_homeland",
"api - 20150702r1_6.36_homeland"
]
}
如果需要,可以将其中任何一个放在一行上:
- debug:
msg: "{% for result in php_command_result.results %}{{ result.key }} - {{ result.value.svn_tag }} | {% endfor %}"
- debug:
msg: "{% set output = [] %}{% for result in php_command_result.results %}{{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}{% endfor %}{{ output }}"
这是另一个使用 filter_plugins
的答案,我发现它非常容易使用。
如果有人仍然需要这个你可以使用下面的代码(输入playbooks/filter_plugins/mapattributes.py):
#!/usr/bin/env python
class FilterModule(object):
def filters(self):
return { 'mapattributes': self.mapattributes }
def mapattributes(self, list_of_dicts, list_of_keys):
l = []
for di in list_of_dicts:
newdi = { }
for key in list_of_keys:
# newdi[key] = di[key]
if di.get(key, None) != None:
newdi[key] = di[key]
l.append(newdi)
return l
假设你有这个列表,你只需要输入来自:
INTERFACES:
- { name: GigabitEthernet1/0/24 , enabled: yes, state: up , description: FRONT }
- { name: GigabitEthernet1/0/9 , enabled: yes, state: up , description: BACK }
让我们创建另一个变量过滤只需要 key:values
test: "{{ INTERFACES | mapattributes(['name', 'description']) }}"
测试输出
- debug:
var: test
ok: [R1] => {
"test": [
{
"description": "FRONT",
"name": "GigabitEthernet1/0/24"
},
{
"description": "BACK",
"name": "GigabitEthernet1/0/9"
}
]
}
这让我有一个大字典,只切分我需要传递给 ios_interface/aggregate
感谢 Nee6ione,我在 pallets/jinja github issue
上找到了它我在搜索处理类似任务的方法时发现了这个问题,但我希望输出是另一个包含各个元素的 JSON 列表。我在 map
、filter
甚至 Jinja2 for
循环上花了很多时间,所以我也会 post 在这里回答。只需创建以下文件并通过 ansible-playbook
:
- hosts: localhost
connection: local
vars:
to_test: [ {'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}, {'value': {'svn_tag': '20150702r1_6.36_homeland'}, 'key': 'api'} ]
tasks:
- debug:
msg: "to_test: {{ to_test }}"
- debug:
msg: "to_test reduced: {{ to_test | json_query('[].{key: key, svn_tag: value.svn_tag}') | list }}"
- debug:
msg: "to_test reduced: {{ to_test | json_query(query1) | list }}"
vars:
query1: "[].{key: key, svn_tag: value.svn_tag}"
最终结果是一个不错的 JSON 数组:
[{'key': 'ui', 'svn_tag': '20150703r1_6.36_homeland'}, {'key': 'api', 'svn_tag': '20150702r1_6.36_homeland'}]"