Ansible 嵌套 group_vars(仅当组 A 和 B 中的成员时使用)

问题描述 投票:0回答:2

我的库存是这样嵌套的:

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"

或者为我需要定位的所有组合创建新组?

ansible var ansible-inventory
2个回答
4
投票

这是建立在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:

使用上述命名约定和

构建的库存插件
使您的类型组(例如
webserversdbservers

)动态化

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
    

1
投票

在你的问题中,你说 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的结构是扁平的。所有主机都是 dbserverwebserver 的成员。 dbserverwebserver 以及 customerAcustomerB 的成员。因此,所有主机都是customerAcustomerB的成员。


限制customerAcustomerB

的成员

声明下面的变量。使名称适合清单 (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') }}"
© www.soinside.com 2019 - 2024. All rights reserved.