正如 Ansible 文档的 散列行为 文章中所建议的:
DEFAULT_HASH_BEHAVIOUR
说明:此设置控制变量在 Ansible 中的合并方式。默认情况下,Ansible 将以特定的优先顺序覆盖变量,如变量中所述。当更高优先级的变量获胜时,它将替换另一个值。一些用户更喜欢合并散列变量(在 Python 术语中也称为“字典”)。此设置称为“合并”。这不是默认行为,它不会影响值为标量(整数、字符串)或数组的变量。我们通常建议不要使用此设置,除非您认为您绝对需要它,并且官方示例 repos 中的剧本不使用此设置在版本 2.0 中添加了combine 过滤器以允许对特定变量执行此操作(描述在过滤器中)。
来源:https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-hash-behaviour
实现此目的的推荐方法是使用combine 过滤器。
也就是说,您的字典中确实有一个列表,这将使其成为一项相当复杂的任务。
将其切换到字典会减轻痛苦:
services:
app:
environment:
RAILS_ENV: development
overridable_var: foo
db:
foo: bar
如果我理解正确,您正在尝试实施 alternative directory layout 的 Ansible 最佳实践。
如果是这种情况,这里可能是一个与您的用例相匹配的解决方案,因为您可以将您的列表转置到字典中的 services 中,如上文所述:
- 在每个环境的 group_var 文件中,将环境名称作为
services 字典键的前缀,例如develop_services
develop_services:
app:
environment:
RAILS_ENV: development
overridable_var: develop from inventories group_vars
- 在您的剧本中,作为第一个任务,甚至作为
pre_task、combine 与您的环境匹配的services 字典,您可以将其作为inventory_file 路径的一部分:
pre_tasks:
- set_fact:
services: "{{ services | combine(vars[inventory_file.split('/')[-2] ~ '_services'], recursive=True) }}"
那就用吧。
给定目录布局:
.
├── group_vars
│ └── app1.yml
├── inventories
│ ├── develop
│ │ ├── group_vars
│ │ │ └── app1.yml
│ │ └── hosts
│ └── staging
│ ├── group_vars
│ │ └── app1.yml
│ └── hosts
└── play.yml
group_vars/app1.yml
services:
app:
environment:
bar: foo
overridable_var: from root group_vars
do_not_override_me: from root group_vars
db:
engine: postgres
库存/开发/主机
all:
children:
app1:
hosts:
app:
inventories/develop/group_vars/app1.yml
develop_services:
app:
environment:
RAILS_ENV: development
overridable_var: develop from inventories group_vars
库存/暂存/主机
all:
children:
app1:
hosts:
app:
inventories/staging/group_vars/app1.yml
staging_services:
app:
environment:
RAILS_ENV: staging
overridable_var: staging from inventories group_vars
play.yml
- hosts: all
gather_facts: no
pre_tasks:
- set_fact:
services: "{{ services | combine(vars[inventory_file.split('/')[-2] ~ '_services'], recursive=True) }}"
tasks:
- debug:
msg: "{{ services }}"
为develop 运行它会给出回顾:
$ ansible-playbook play.yml -i inventories/develop
PLAY [all] *********************************************************************************************************
TASK [set_fact] ****************************************************************************************************
ok: [app]
TASK [debug] *******************************************************************************************************
ok: [app] => {
"msg": {
"app": {
"environment": {
"RAILS_ENV": "development",
"bar": "foo",
"do_not_override_me": "from root group_vars",
"overridable_var": "develop from inventories group_vars"
}
},
"db": {
"engine": "postgres"
}
}
}
PLAY RECAP *********************************************************************************************************
app : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
为staging 运行它会给出回顾:
$ ansible-playbook play.yml -i inventories/staging
PLAY [all] *********************************************************************************************************
TASK [set_fact] ****************************************************************************************************
ok: [app]
TASK [debug] *******************************************************************************************************
ok: [app] => {
"msg": {
"app": {
"environment": {
"RAILS_ENV": "staging",
"bar": "foo",
"do_not_override_me": "from root group_vars",
"overridable_var": "staging from inventories group_vars"
}
},
"db": {
"engine": "postgres"
}
}
}
PLAY RECAP *********************************************************************************************************
app : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
额外说明: 请注意,这将不允许 playbook 同时在两个环境中运行,正如 使用文档的多个库存来源:
请记住,如果清单中存在变量冲突,则根据How variables are merged 和Variable precedence: Where should I put a variable? 中描述的规则解决它们。合并顺序由库存源参数的顺序控制。如果暂存库存中的[all:vars] 定义了myvar = 1,但生产库存定义了myvar = 2,则剧本将使用myvar = 2 运行。如果 playbook 使用 -i production -i staging 运行,结果将被反转。
来源:https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#using-multiple-inventory-sources