我的库存是这样嵌套的:
customerA:
children:
webserver:
hosts:
host1:
host2:
dbserver:
hosts:
host3:
host4:
customerB:
children:
webserver:
hosts:
host5:
host6:
dbserver:
hosts:
host7:
host8:
所以对于
host1
ansible负载:
host_vars/host1
group_vars/customerA
group_vars/webserver
有没有办法创建库存管理使用的
nested_vars/customerA/webserver.yml
(与nested_vars/webserver/customerA.yml
相同)结构?
或者我必须使用类似的东西
group_vars/customerA
- parent: "customerA"
group_vars/webserver:
- child: "webserver"
在每本剧本中:
include_vars:
file: "{{ parent }}+{{ child }}.yml"
或者为我需要定位的所有组合创建新组?
这是建立在this other answer
创建您的基础静态库存
inventories/default/0-hosts.yml
---
customerA:
children:
customerA_webservers:
hosts:
host1:
host2:
customerA_dbservers:
hosts:
host3:
host4:
customerB:
children:
customerB_webservers:
hosts:
host5:
host6:
customerB_dbservers:
hosts:
host7:
host8:
使用上述命名约定和
构建的库存插件
使您的类型组(例如
webservers
,dbservers
)动态化
inventories/default/1-typegroups_constructed.yml
---
plugin: constructed
groups:
dbservers: group_names | select('match', '^.*_dbservers$') | length > 0
webservers: group_names | select('match', '^.*_webservers$') | length > 0
您现在拥有完整的细粒度组成员资格:
$ ansible-inventory -i inventories/default/ --list
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"ungrouped",
"customerA",
"customerB",
"webservers",
"dbservers"
]
},
"customerA": {
"children": [
"customerA_webservers",
"customerA_dbservers"
]
},
"customerA_dbservers": {
"hosts": [
"host3",
"host4"
]
},
"customerA_webservers": {
"hosts": [
"host1",
"host2"
]
},
"customerB": {
"children": [
"customerB_webservers",
"customerB_dbservers"
]
},
"customerB_dbservers": {
"hosts": [
"host7",
"host8"
]
},
"customerB_webservers": {
"hosts": [
"host5",
"host6"
]
},
"dbservers": {
"hosts": [
"host3",
"host4",
"host7",
"host8"
]
},
"webservers": {
"hosts": [
"host1",
"host2",
"host5",
"host6"
]
}
}
这使您能够解决:
inventories/default/group_vars/customerA.yml
inventories/default/group_vars/dbservers.yml
inventories/default/group_vars/customerB_webservers.yml
在你的问题中,你说 host1 加载:
host_vars/host1
group_vars/customerA
group_vars/webserver
这还不完整。 host1 还加载 group_vars/customerB。为了证明它运行下面的剧本
- hosts: all
tasks:
- debug:
var: groups|to_yaml
run_once: true
给(删节)
groups:
all: [host1, host2, host5, host6, host3, host4, host7, host8]
customerA: [host1, host2, host5, host6, host3, host4, host7, host8]
customerB: [host1, host2, host5, host6, host3, host4, host7, host8]
dbserver: [host3, host4, host7, host8]
ungrouped: []
webserver: [host1, host2, host5, host6]
Ansible inventory的结构是扁平的。所有主机都是 dbserver 或 webserver 的成员。 dbserver 和 webserver 以及 customerA 和 customerB 的成员。因此,所有主机都是customerA和customerB的成员。
限制customerA和customerB
的成员声明下面的变量。使名称适合清单 (hosts)
nv_inv: "{{ lookup('file', 'hosts')|from_yaml }}"
nv_groups_0_keys: "{{ nv_inv|json_query('keys(@)') }}"
nv_groups_0_vals: "{{ nv_inv|json_query('*.children[].*.keys(hosts)')|map('flatten') }}"
nv_groups_0: "{{ dict(nv_groups_0_keys|zip(nv_groups_0_vals)) }}"
nv_groups: "{{ groups|combine(nv_groups_0) }}"
nv_hosts_str: |
{% for h in nv_groups.all %}
{{ h }}: {{ nv_groups|dict2items|selectattr('value', 'contains', h)|map(attribute='key') }}
{% endfor %}
nv_hosts: "{{ nv_hosts_str|from_yaml }}"
这将创建您的组字典
nv_groups:
all: [host1, host2, host5, host6, host3, host4, host7, host8]
customerA: [host1, host2, host3, host4]
customerB: [host5, host6, host7, host8]
dbserver: [host3, host4, host7, host8]
ungrouped: []
webserver: [host1, host2, host5, host6]
和主人
nv_hosts:
host1: [all, customerA, webserver]
host2: [all, customerA, webserver]
host3: [all, customerA, dbserver]
host4: [all, customerA, dbserver]
host5: [all, webserver, customerB]
host6: [all, webserver, customerB]
host7: [all, dbserver, customerB]
host8: [all, dbserver, customer]
嵌套变量
你可以自己创建这样的框架。例如,创建以下文件。每个文件的名称是主机必须加入的组的列表,以破折号分隔。文件名中组的顺序并不重要。文件 all.yml 将按预期工作
shell> tree nested_vars/
nested_vars/
├── dbserver-customerB.yml
├── webserver-customerA.yml
└── webserver-customerB.yml
0 directories, 3 files
shell> cat nested_vars/dbserver-customerB.yml
nested_dbserver_customerB: nested_dbserver_customerB value
shell> cat nested_vars/webserver-customerA.yml
nested_webserver_customerA: nested_webserver_customerA value
shell> cat nested_vars/webserver-customerB.yml
nested_webserver_customerB: nested_webserver_customerB value
声明下面的变量。适合目录(nested_vars)
nv_glob: "{{ playbook_dir }}/nested_vars/*.yml"
nv_files: "{{ query('fileglob', nv_glob) }}"
nv_files_groups: "{{ nv_files|map('basename')|map('splitext')|map('first')|map('split', '-') }}"
nv_files_dict: "{{ dict(nv_files|zip(nv_files_groups)) }}"
nv_files_list: "{{ nv_files_dict|dict2items(key_name='file', value_name='groups') }}"
这将创建文件列表
nv_files_list:
- file: /export/scratch/tmp7/test-220/nested_vars/webserver-customerA.yml
groups: [webserver, customerA]
- file: /export/scratch/tmp7/test-220/nested_vars/webserver-customerB.yml
groups: [webserver, customerB]
- file: /export/scratch/tmp7/test-220/nested_vars/dbserver-customerB.yml
groups: [dbserver, customer]
包括来自nested_vars
的文件 - include_vars: "{{ item.file }}"
loop: "{{ nv_files_list }}"
loop_control:
label: "{{ item.file|basename }}"
when: item.groups|intersect(nv_hosts[inventory_hostname])|length == item.groups|length
给出(ANSIBLE_DISPLAY_SKIPPED_HOSTS=true)
TASK [include_vars] **************************************************************************
ok: [host1] => (item=webserver-customerA.yml)
ok: [host2] => (item=webserver-customerA.yml)
ok: [host5] => (item=webserver-customerB.yml)
ok: [host6] => (item=webserver-customerB.yml)
ok: [host7] => (item=dbserver-customerB.yml)
ok: [host8] => (item=dbserver-customerB.yml)
测试一下
- debug:
msg: "{{ lookup('vars', *q('varnames', 'nested_*')) }}"
给予
TASK [debug] *********************************************************************************
ok: [host1] =>
msg: nested_webserver_customerA value
ok: [host2] =>
msg: nested_webserver_customerA value
ok: [host5] =>
msg: nested_webserver_customerB value
ok: [host6] =>
msg: nested_webserver_customerB value
ok: [host3] =>
msg: []
ok: [host4] =>
msg: []
ok: [host7] =>
msg: nested_dbserver_customerB value
ok: [host8] =>
msg: nested_dbserver_customerB value
完整的测试项目示例
shell> tree .
.
├── ansible.cfg
├── group_vars
│ └── all
│ ├── nv_files.yml
│ └── nv_hosts.yml
├── hosts
├── nested_vars
│ ├── dbserver-customerB.yml
│ ├── webserver-customerA.yml
│ └── webserver-customerB.yml
└── pb.yml
3 directories, 8 files
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
shell> cat hosts
customerA:
children:
webserver:
hosts:
host1:
host2:
dbserver:
hosts:
host3:
host4:
customerB:
children:
webserver:
hosts:
host5:
host6:
dbserver:
hosts:
host7:
host8:
shell> cat pb.yml
- hosts: all
pre_tasks:
- block:
- debug:
var: nv_inv
- debug:
var: nv_groups_0|to_yaml
- debug:
var: nv_groups|to_yaml
- debug:
var: nv_hosts|to_yaml
- debug:
var: nv_files
- debug:
var: nv_files_groups
- debug:
var: nv_files_dict
- debug:
var: nv_files_list|to_yaml
run_once: true
when: debug|d(false)|bool
- include_vars: "{{ item.file }}"
loop: "{{ nv_files_list }}"
loop_control:
label: "{{ item.file|basename }}"
when: item.groups|intersect(nv_hosts[inventory_hostname])|length == item.groups|length
tasks:
- debug:
msg: |
customerA: {{ groups.customerA }}
customerB: {{ groups.customerB }}
webserver: {{ groups.webserver }}
dbserver: {{ groups.dbserver }}
run_once: true
when: native|d(false)|bool
- debug:
msg: "{{ lookup('vars', *q('varnames', 'nested_*')) }}"
shell> cat group_vars/all/nv_hosts.yml
nv_inv: "{{ lookup('file', 'hosts')|from_yaml }}"
nv_groups_0_keys: "{{ nv_inv|json_query('keys(@)') }}"
nv_groups_0_vals: "{{ nv_inv|json_query('*.children[].*.keys(hosts)')|map('flatten') }}"
nv_groups_0: "{{ dict(nv_groups_0_keys|zip(nv_groups_0_vals)) }}"
nv_groups: "{{ groups|combine(nv_groups_0) }}"
nv_hosts_str: |
{% for h in nv_groups.all %}
{{ h }}: {{ nv_groups|dict2items|selectattr('value', 'contains', h)|map(attribute='key') }}
{% endfor %}
nv_hosts: "{{ nv_hosts_str|from_yaml }}"
shell> cat group_vars/all/nv_files.yml
nv_glob: "{{ playbook_dir }}/nested_vars/*.yml"
nv_files: "{{ query('fileglob', nv_glob) }}"
nv_files_groups: "{{ nv_files|map('basename')|map('splitext')|map('first')|map('split', '-') }}"
nv_files_dict: "{{ dict(nv_files|zip(nv_files_groups)) }}"
nv_files_list: "{{ nv_files_dict|dict2items(key_name='file', value_name='groups') }}"