在我的有效载荷中,我有一个变量实际上是一个字典列表,例如这个:
myvar:
- name: name1
ip_addresses:
- 10.10.10.10
- 11.11.11.11
nat_destination_addresses:
- host: 12.12.12.12
destination: 13.13.13.13
- host: 14.14.14.14
destination: 15.15.15.15
nat_source_address: 16.16.16.16
applications:
- protocol: tcp
port: 8302
- protocol: udp
port: 2000
- protocol: tcp
port: 2000-5600
- name: name2
ip_addresses:
- 17.17.17.17
- name: name3
ip_addresses:
- 18.18.18.18
- 19.19.19.19
myvar
中每个元素的所有值都是可选的,但名称除外,这是必需的。
我正在尝试填充IP地址(ip_addresses
,nat_destination_addresses
和nat_source_address
)和端口。端口的长度应为五个字符,开头为零(2000
变为02000
,2000-5600
变为02000-05600
),每个子节点的IP地址应为三个字符(18.18.18.18
变为018.018.018.018
)。
我遇到的问题是我无法仅更改myvar
的子部分。
我在这里已经阅读了其他问题,例如:
merging dictionaries in ansible
Using set_facts and with_items together in Ansible
但无济于事。无论我做什么,我都无法保留原始字典,如果我使用第二个StackOverflow链接中的combine
过滤器,我最终会得到一个ip_addresses列表。
预期结果是具有更新的IP地址和端口的原始myvar
变量。
答案 0 :(得分:2)
这似乎是将逻辑投入自定义Ansible模块的好时机。它不一定是任何花哨的东西,例如:
vm.dtIsHidden = whatever;
如果我将上述内容放入from ansible.module_utils.basic import AnsibleModule
def pad_addr(addr):
return '.'.join('%03d' % int(x) for x in addr.split('.'))
def main():
module_args = dict(
data=dict(type='list', required=True),
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
data = module.params['data']
for d in data:
if 'ip_addresses' in d:
d['ip_addresses'] = [pad_addr(x) for x in d['ip_addresses']]
if 'nat_destination_addresses' in d:
for dest in d['nat_destination_addresses']:
dest['host'] = pad_addr(dest['host'])
dest['destination'] = pad_addr(dest['destination'])
if 'nat_source_address' in d:
d['nat_source_address'] = pad_addr(d['nat_source_address'])
if 'applications' in d:
for service in d['applications']:
service['port'] = '%05d' % service['port']
module.exit_json(changed=False,
result=data)
if __name__ == '__main__':
main()
,然后运行以下剧本:
library/pad_data.py
我得到了结果:
- hosts: localhost
gather_facts: false
vars:
myvar:
- name: name1
ip_addresses:
- 10.10.10.10
- 11.11.11.11
nat_destination_addresses:
- host: 12.12.12.12
destination: 13.13.13.13
- host: 14.14.14.14
destination: 15.15.15.15
nat_source_address: 16.16.16.16
applications:
- protocol: tcp
port: 8302
- protocol: udp
port: 2000
- protocol: tcp
port: 2000
- name: name2
ip_addresses:
- 17.17.17.17
- name: name3
ip_addresses:
- 18.18.18.18
- 19.19.19.19
tasks:
- pad_data:
data: "{{ myvar }}"
register: padded
- debug:
var: padded.result
答案 1 :(得分:0)
Larsks的回答很明确,可能是大多数人的最佳解决方案,但我的要求是限制使用Python为这个项目创建的模块数量,所以这是我的解决方法以供参考。
基本上,我在这个样本中所做的是:
<强>本地:强>
我接受myvar
,我将其输出到yml文件(文件顶部带有“---”,并确保myvar
仍然设置为密钥。
使用regexp和替换模块,我替换了要替换的文件部分。
在我的所有主机上:
我重新加载(现在)格式正确的myvar
并使用myvar
替换旧的include_vars
变量
---
- name: Customer {{ customer_id }} - Format the ip addresses and ports
hosts: localhost
gather_facts: no
connection: local
tags: [format_vars]
tasks:
- name: Copy the 'myvar' content to a local file to allow ip addresses
and ports formatting
copy:
content: "---\n{{ { 'myvar': myvar} | to_nice_yaml(indent=2) }}"
dest: "{{ formatted_myvar_file }}"
- name: Pad all ip addresses parts with two zeroes to ensure that all parts have at least three numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})'
replace: '00\1.00\2.00\3.00\4'
- name: Remove extra zeroes from ip addresses to ensure that all of their parts have exactly three numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: '\d{0,2}(\d{3})\.\d{0,2}(\d{3})\.\d{0,2}(\d{3})\.\d{0,2}(\d{3})'
replace: '\1.\2.\3.\4'
- name: Pad all ports with four zeroes to ensure that they all have at least five numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: 'port: (\d{1,5})'
replace: 'port: 0000\1'
- name: Remove extra zeroes from ports to ensure that they all have exactly five numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: 'port: \d{0,4}(\d{5})'
replace: 'port: \1'
- name: Pad all second parts of port ranges with four zeroes to ensure that they all have at least five numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: 'port: (\d{5})-(\d{1,5})'
replace: 'port: \1-0000\2'
- name: Remove extra zeroes from second parts of port ranges to ensure that they all have exactly five numbers
replace:
path: "{{ formatted_myvar_file }}"
regexp: 'port: (\d{5})-\d{0,4}(\d{5})'
replace: 'port: \1-\2'
- name: Customer {{ customer_id }} - Load the properly formatted ip addresses and ports
hosts: localhost:all-n7k:srx-clu:all-mx80:all-vsrx
gather_facts: no
connection: local
tags: [format_vars]
tasks:
- include_vars:
file: "{{ formatted_myvar_file }}"
ignore_errors: yes