问:
“读取JSON文件并将值替换或添加到数据结构中。”
上下文:模块的F5文档
bigip_do_deploy
建议如何动态创建内容。然而
样板
插件
documentation
说“模板查找插件……不是一种鼓励的做法……应该只用于绝对最小的配置”,原因很荒谬,“以防止你的行动手册变得太大”:
所容纳之物
:要在系统上配置的声明。
此参数最常与
文件或模板查找插件
。有关正确用法,请参阅示例部分。
对于任何高级或带有格式的内容,请考虑使用模板查找。这还可以用于直接在YAML中指定应用程序服务配置,但是
不是鼓励的做法
并且,如果使用的话,应该只用于绝对最小的配置
防止你的花花公子变得太大
。如果您的内容包含加密值(如密文、密码短语等),则返回的更改值将始终为true。如果您使用to_nice_json过滤器,它将导致该模块失败,因为该过滤器的目的是将json格式化为可读的,并且该过程包括插入“破坏json验证器的额外字符”。
A: 你的尝试毫无意义。你应该使用
templating
即使
文档
是说这不是一种鼓励的做法。
Templating
是Ansible的核心功能,应在需要时广泛使用。
在这个解决方案中,想法是在YAML中创建内容,并将其转换为JSON,作为最后一步。从技术上讲,这意味着转换您的文件
{{ ansible_host }}.json
到模板
{{ ansible_host }}.yaml.j2
和使用
template
查找插件
tasks:
- name: Deploy the DO Code to the F5
bigip_do_deploy:
content: '{{ lookup("template", template)|from_yaml|to_json }}'
dry_run: "{{ dryrun }}"
register: result
vars:
template: "{{ ansible_host }}.yaml.j2"
注意事项:
在第一个示例中,对所有组件分别进行了解释和测试。在第二个示例中,使用相同的组件来动态创建内容,并将敏感数据的范围限制为单个任务。最后一个示例显示了如何将多个模板与多个主机和网络设备一起使用。这些示例没有提供网络设备的有效配置。目标是展示如何使用具有多个变量源的模板(group_var、host_var、play-var、task-var、vault文件等)。
示例1。创建YAML配置文件
有很多选择
setup
可靠。例如,让我们创建下面的简单项目进行测试
shell> tree .
.
âââ ansible.cfg
âââ files
âââ group_vars
â  âââ all
â  âââ net_dev_common.yml
â  âââ net_dev_vault.yml
âââ hosts
âââ pb.yml
âââ templates
âââ net_dev.yaml.j2
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
retry_files_enabled = false
stdout_callback = yaml
在中创建通用变量
group_vars/all
shell> cat group_vars/all/net_dev_common.yml
nd_dns_common: [8.8.8.8, 8.8.4.4]
在中创建通用vault变量
group_vars/all
shell> cat group_vars/all/net_dev_vault.yml
nd_passwd:
nd1: passwd_for_nd1
nd2: passwd_for_nd2
nd3: passwd_for_nd3
Encrypt
文件
shell> ansible-vault encrypt group_vars/all/net_dev_vault.yml
Encryption successful
shell> cat group_vars/all/net_dev_vault.yml
$ANSIBLE_VAULT;1.1;AES256
64373537613238313530376438313030643339383336313436363738343637646362626430396236
6135646536323563336539663364313966633066353231610a353365306338633338646261326661
31613062393934303331626238623836383862616338636564393630613865356333363239373731
6639383961356635640a663565336238613232346331663363616438666532646532663137333930
37323537306264633161326433646131353162323136343434316166616432313465626632643161
65616136386166336331306134613163353630306562333765373839623831356562313365306563
62333464303264646139323065663739633262663131666231646638643134666433653961366665
35626230316533323761
创建简单库存
shell> cat hosts
localhost
创建一个简单的测试模板。为了更好的可读性,该模板将在YAML中创建配置文件。所有三个参数都将动态设置
shell> cat templates/net_dev.yaml.j2
{% filter from_yaml %}
device: {{ item }}
dns: {{ nd_dns_common }}
passwd: {{ nd_passwd[item] }}
{% endfilter %}
例如,下面播放
shell> cat pb.yml
- hosts: localhost
vars:
net_devs: [nd1, nd2, nd3]
tasks:
- name: Create configuration files
copy:
dest: "{{ playbook_dir }}/files/{{ item }}.yaml"
content: "{{ lookup('template', 'net_dev.yaml.j2')|to_nice_yaml }}"
loop: "{{ net_devs }}"
when: nd_init|d(false)|bool
给予
shell> ansible-playbook pb.yml -e nd_init=true
PLAY [localhost] ******************************************************************************
TASK [Create configuration files] *************************************************************
changed: [localhost] => (item=nd1)
changed: [localhost] => (item=nd2)
changed: [localhost] => (item=nd3)
并创建配置文件
shell> tree files/
files/
âââ nd1.yaml
âââ nd2.yaml
âââ nd3.yaml
0 directories, 3 files
shell> cat files/nd1.yaml
device: nd1
dns:
- 8.8.8.8
- 8.8.4.4
passwd: passwd_for_nd1
shell> cat files/nd2.yaml
device: nd2
dns:
- 8.8.8.8
- 8.8.4.4
passwd: passwd_for_nd2
shell> cat files/nd3.yaml
device: nd3
dns:
- 8.8.8.8
- 8.8.4.4
passwd: passwd_for_nd3
读取配置文件并将内容转换为JSON
- name: Test configuration files
command: echo '{{ content|to_json }}'
loop: "{{ net_devs }}"
register: out
vars:
file: "files/{{ item }}.yaml"
content: "{{ lookup('file', file)|from_yaml }}"
when: nd_deploy|d(false)|bool
- debug:
msg: "{{ out.results|map(attribute='stdout') }}"
when: nd_deploy|d(false)|bool
以下调试任务显示筛选器
to_json
将文件的内容转换为
valid JSON
shell> ansible-playbook pb.yml -e nd_deploy=true
PLAY [localhost] ******************************************************************************
TASK [Create configuration files] *************************************************************
skipping: [localhost] => (item=nd1)
skipping: [localhost] => (item=nd2)
skipping: [localhost] => (item=nd3)
skipping: [localhost]
TASK [Test configuration files] ***************************************************************
changed: [localhost] => (item=nd1)
changed: [localhost] => (item=nd2)
changed: [localhost] => (item=nd3)
TASK [debug] **********************************************************************************
ok: [localhost] =>
msg:
- '{"device": "nd1", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd1"}'
- '{"device": "nd2", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd2"}'
- '{"device": "nd3", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd3"}'
PLAY RECAP ************************************************************************************
localhost: ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
完整的测试剧本示例
shell> cat pb.yml
- hosts: localhost
vars:
net_devs: [nd1, nd2, nd3]
tasks:
- name: Create configuration files
copy:
dest: "{{ playbook_dir }}/files/{{ item }}.yaml"
content: "{{ lookup('template', 'net_dev.yaml.j2')|to_nice_yaml }}"
loop: "{{ net_devs }}"
when: nd_init|d(false)|bool
- name: Test configuration files
command: echo '{{ content|to_json }}'
loop: "{{ net_devs }}"
register: out
vars:
file: "files/{{ item }}.yaml"
content: "{{ lookup('file', file)|from_yaml }}"
when: nd_deploy|d(false)|bool
- debug:
msg: "{{ out.results|map(attribute='stdout') }}"
when: nd_deploy|d(false)|bool
示例2。动态创建内容。将密码的范围限制为单个任务。
在第一个示例中,存储在字典中的密码
nd_passwd
,在整部剧的范围内都有。解密后的密码也存储在文件中
files/nd*.yml
.在这个项目中,我们限制了变量的范围
nd_passwd
到单个任务并动态创建内容
shell> tree .
.
âââ ansible.cfg
âââ files
â  âââ net_dev_vault.yml
âââ group_vars
â  âââ all
â  âââ net_dev_common.yml
âââ hosts
âââ pb.yml
âââ templates
âââ net_dev.yaml.j2
我们移动了文件
net_dev_svault.yml
从…起
group_vars/all
进入目录
文件
并更新了剧本。其他文件与第一个示例中的相同。
shell> cat pb.yml
- hosts: localhost
vars:
net_devs: [nd1, nd2, nd3]
tasks:
- name: Test configuration files
command: echo '{{ content|to_json }}'
loop: "{{ net_devs }}"
register: out
vars:
content: "{{ lookup('template', 'net_dev.yaml.j2')|from_yaml }}"
vault: "{{ lookup('file', 'net_dev_vault.yml')|from_yaml }}"
nd_passwd: "{{ vault.nd_passwd }}"
- debug:
msg: "{{ out.results|map(attribute='stdout') }}"
下面的调试任务显示了查找插件
样板
与过滤器一起
to_json
动态创建了相同的有效JSON内容
shell> ansible-playbook pb.yml
PLAY [localhost] ******************************************************************************
TASK [Test configuration files] ***************************************************************
changed: [localhost] => (item=nd1)
changed: [localhost] => (item=nd2)
changed: [localhost] => (item=nd3)
TASK [debug] **********************************************************************************
ok: [localhost] =>
msg:
- '{"device": "nd1", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd1"}'
- '{"device": "nd2", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd2"}'
- '{"device": "nd3", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd3"}'
PLAY RECAP ************************************************************************************
localhost: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例3。多个模板、多个主机和多个网络设备
在以下项目中
shell> tree .
.
âââ ansible.cfg
âââ files
â  âââ net_dev_vault.yml
âââ group_vars
â  âââ all
â  âââ net_dev_common.yml
âââ hosts
âââ host_vars
â  âââ host1
â  â  âââ nd_local.yml
â  âââ host2
â  âââ nd_local.yml
âââ pb.yml
âââ templates
âââ net_dev_default.yaml.j2
âââ net_dev_extended.yaml.j2
创建两个模板
shell> cat templates/net_dev_default.yaml.j2
{% filter from_yaml %}
device: {{ item }}
dns: {{ nd_dns_common }}
passwd: {{ nd_passwd[item] }}
{% endfilter %}
shell> cat templates/net_dev_extended.yaml.j2
{% filter from_yaml %}
device: {{ item }}
dns: {{ nd_dns_common }}
passwd: {{ nd_passwd[item] }}
is_clustered: {{ nd_clustered[item]|d(nd_clustered.default) }}
is_license_expired: {{ nd_expired[item]|d(true) }}
is_virtual: {{ nd_virtual[item]|d(false) }}
{% endfilter %}
将两台主机放入库存
shell> cat hosts
[test]
host1 ansible_host=test_11
host2 ansible_host=test_13
并创建
主机虚拟机(_V)
shell> cat host_vars/host1/nd_local.yml
net_devs: [nd1, nd2, nd3]
net_devs_templates:
net_dev_default: [nd1]
net_dev_extended: [nd2, nd3]
nd_clustered:
default: false
nd3: true
nd_expired:
default: true
nd3: false
nd_virtual:
default: false
nd3: true
shell> cat host_vars/host2/nd_local.yml
net_devs: [nd1, nd2]
net_devs_templates:
net_dev_default: [nd1]
net_dev_extended: [nd2]
nd_clustered:
default: false
nd2: true
nd_expired:
default: true
nd2: false
nd_virtual:
default: false
nd2: true
剧本
shell> cat pb.yml
- hosts: all
tasks:
- name: Test configuration files
command: echo '{{ lookup("template", template)|from_yaml|to_json }}'
loop: "{{ net_devs }}"
register: out
vars:
template: "{{ net_devs_templates|dict2items|
selectattr('value', 'contains', item)|
map(attribute='key')|first }}.yaml.j2"
vault: "{{ lookup('file', 'net_dev_vault.yml')|from_yaml }}"
nd_passwd: "{{ vault.nd_passwd }}"
- debug:
msg: "{{ out.results|map(attribute='stdout') }}"
给予
shell> ansible-playbook pb.yml
PLAY [all] **************************************************************************************************************************************************
TASK [Test configuration files] *****************************************************************************************************************************
changed: [host1] => (item=nd1)
changed: [host2] => (item=nd1)
changed: [host2] => (item=nd2)
changed: [host1] => (item=nd2)
changed: [host1] => (item=nd3)
TASK [debug] ************************************************************************************************************************************************
ok: [host1] =>
msg:
- '{"device": "nd1", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd1"}'
- '{"device": "nd2", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd2", "is_clustered": false, "is_license_expired": true, "is_virtual": false}'
- '{"device": "nd3", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd3", "is_clustered": true, "is_license_expired": false, "is_virtual": true}'
ok: [host2] =>
msg:
- '{"device": "nd1", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd1"}'
- '{"device": "nd2", "dns": ["8.8.8.8", "8.8.4.4"], "passwd": "passwd_for_nd2", "is_clustered": true, "is_license_expired": false, "is_virtual": true}'
PLAY RECAP **************************************************************************************************************************************************
host1: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0