【问题标题】:Managing "nested" group in Ansible YAML inventory files在 Ansible YAML 清单文件中管理“嵌套”组
【发布时间】:2021-08-11 17:59:37
【问题描述】:

我正在管理多个集群,我想将多个清单文件整合到一个清单中,看起来像这样:

all:
  children:
    cluster_one:
      children:
        controller:
          hosts:
            host1:
            host2:
            host3:
        compute:
          hosts:
            host4:
            host5:
            host6:
    cluster_two:
      children:
        controller:
          hosts:
            host11:
            host12:
            host13:

我原以为最终会像这样解析:

[cluster_one]
host1
host2
host3
host4
host5
host6

[cluster_two]
host11
host12
host13

[controller]
host1
host2
host3
host11
host12
host13

[compute]
host4
host5
host6

有了这个结构,我就可以要求“控制器在 cluster_one" 与主机模式cluster_one:&controller,或者如果 我想要我可以要求的所有集群中的所有控制器 controller。方便!

不幸的是,它实际上是这样解析的:

[cluster_one]
host1
host2
host3
host4
host5
host6

[cluster_two]
host11
host12
host13

[controller]
host1
host2
host3
host11
host12
host13

[compute]
host4
host5
host6

[cluster_one:children]
controller
compute

[cluster_two:children]
controller

请注意底部的两个额外条目,它们构成 controllercompute 将他们尊敬的“父母”的孩子分组在 YAML 文件,而不是仅将其 hosts 成员设为 父母。

例如,如果我运行ansible -i example.yml --list-hosts cluster_one,我会得到:

  hosts (9):
    host1
    host2
    host3
    host10
    host11
    host12
    host4
    host5
    host6

这是出乎意料的,让我很难过。我显然可以重组 库存,以便它工作(例如,通过使用 INI 格式的库存 此处显示,或为类似结构重新构建 YAML),但是 这些解决方案涉及多次列出每个主机,这意味着 事情可能不同步。

有没有一种方法来构建库存,让我分组 不想在多个组中显式列出主机?

【问题讨论】:

  • 我认为您对--list-hosts 的结果有误。 host10 应该是 host13 ?

标签: ansible ansible-inventory


【解决方案1】:

通过使用类似于@Zeitounator 建议的库存布局 并利用constructed库存插件,我已经能够 得到我想要的。我从一个静态库存开始 inventory/static/clusters.yml 看起来像:

all:
  children:
    cluster_one:
      children:
        cluster_one_controller:
          vars:
            node_role: controller
          hosts:
            host1:
            host2:
            host3:
        cluster_one_compute:
          vars:
            node_role: compute
          hosts:
            host4:
            host5:
            host6:
    cluster_two:
      children:
        cluster_two_controller:
          vars:
            node_role: controller
          hosts:
            host11:
            host12:
            host13:

然后我将以下库存从 inventory/dynamic/constructed.yml:

plugin: constructed
strict: false
keyed_groups:
  - prefix: ""
    separator: ""
    key: node_role

还有一个ansible.cfg,看起来像:

[defaults]
inventory = inventory/static,inventory/dynamic

(确保constructed 库存加载静态 库存,而不是试图手动订购文件名)。


有了以上内容,我可以在 cluster_one 上运行任务:

ansible cluster_one ...

或在所有控制器上:

ansible controller ...

或者只是在cluster_two中的控制器上:

ansible 'cluster_two:&controller' ...

等等

(对于最后一个例子,我当然可以写cluster_two_controller 而不是cluster_two:&controller,但我喜欢十字路口 语法,因为它符合我正在尝试做的事情的心理地图。)

【讨论】:

    【解决方案2】:

    使用 constructed 库存插件在最新 @larsk 的回答中建立输入。下面的原始答案


    如果您对集群组/子组保持相同的命名约定,则可以使用构建的插件进行更多的 DRY,从而无需在组中引入额外的变量。

    请注意,在库存目录中使用文件名约定允许库存源的自然加载顺序,而无需修改ansible.cfg

    鉴于以下最小的inventories/cluster/cluster.yml 静态库存源:

    ---
    all:
      children:
        cluster_one:
          children:
            cluster_one_controller:
              hosts:
                host1:
                host2:
                host3:
            cluster_one_compute:
              hosts:
                host4:
                host5:
                host6:
        cluster_two:
          children:
            cluster_two_controller:
              hosts:
                host11:
                host12:
                host13:
    

    以及基于现有组名检测对应的inventories/cluster/cluster_constructed.yml动态库存源:

    ---
    plugin: constructed
    strict: false
    groups:
      controller: group_names | select('match', '^.*_controller$') | length > 0
      compute: group_names | select('match', '^.*_compute$') | length > 0
    

    我们使用我们的复合库存目录得到预期的结果

    $ ansible-inventory -i inventories/cluster --list
    {
        "_meta": {
            "hostvars": {}
        },
        "all": {
            "children": [
                "cluster_one",
                "cluster_two",
                "compute",
                "controller",
                "ungrouped"
            ]
        },
        "cluster_one": {
            "children": [
                "cluster_one_compute",
                "cluster_one_controller"
            ]
        },
        "cluster_one_compute": {
            "hosts": [
                "host4",
                "host5",
                "host6"
            ]
        },
        "cluster_one_controller": {
            "hosts": [
                "host1",
                "host2",
                "host3"
            ]
        },
        "cluster_two": {
            "children": [
                "cluster_two_controller"
            ]
        },
        "cluster_two_controller": {
            "hosts": [
                "host11",
                "host12",
                "host13"
            ]
        },
        "compute": {
            "hosts": [
                "host4",
                "host5",
                "host6"
            ]
        },
        "controller": {
            "hosts": [
                "host1",
                "host11",
                "host12",
                "host13",
                "host2",
                "host3"
            ]
        }
    }
    

    原始答案


    我很抱歉这让你难过@larks。不幸的是,正如您刚刚经历的那样:

    • 组的内容不取决于您定义它的位置,最终将是所有主机/子定义的合并。
    • 在任何地方定义为子级的组将包含在其他地方定义的所有主机。

    我能想到的唯一静态 yaml 库存定义尽可能接近您的初始要求并尽可能尊重 DRY 原则:

    ---
    all:
      children:
        cluster_one:
          children:
            cluster_one_controller:
              hosts:
                host1:
                host2:
                host3:
            cluster_one_compute:
              hosts:
                host4:
                host5:
                host6:
        cluster_two:
          children:
            cluster_two_controller:
              hosts:
                host11:
                host12:
                host13:
        controller:
          children:
            cluster_one_controller:
            cluster_two_controller:
        compute:
          children:
            controller_one_compute:
    

    这将让您选择以下任何模式(非详尽列表):

    • 一个完整的集群,例如cluster_one
    • 集群的所有控制器,例如cluster_two_controllercluster_two:&controller
    • 跨集群的所有计算节点,例如compute
    • ...

    希望这将有助于照亮您的白天(或夜晚......)

    【讨论】:

      【解决方案3】:

      在剧本中编写代码需要多少?给定字典中的结构

      shell> cat _hosts
      all:
        cluster_one:
          controller:
            - host1
            - host2
            - host3
          compute:
            - host4
            - host5
            - host6
        cluster_two:
          controller:
            - host11
            - host12
            - host13
      

      该剧创建了组的字典

      - hosts: localhost
        vars:
          inv: "{{ lookup('file', '_hosts')|from_yaml }}"
        tasks:
          - name: all
            set_fact:
              _groups: "{{ _groups|d({})|combine({'all': _hosts}) }}"
            vars:
              _hosts: "{{ inv.all|json_query('*.*')|flatten }}"
          - name: clusters
            set_fact:
              _groups: "{{ _groups|combine({item: _hosts}) }}"
            loop: "{{ inv.all.keys()|list }}"
            vars:
              _hosts: "{{ inv.all|json_query(item ~ '.*')|flatten }}"
          - name: sub_clusters
            set_fact:
              _groups: "{{ _groups|combine(item, list_merge='append') }}"
            loop: "{{ inv.all|json_query('*') }}"
          - debug:
              var: _groups
      

      给予

        _groups:
          all:
          - host1
          - host2
          - host3
          - host4
          - host5
          - host6
          - host11
          - host12
          - host13
          cluster_one:
          - host1
          - host2
          - host3
          - host4
          - host5
          - host6
          cluster_two:
          - host11
          - host12
          - host13
          compute:
          - host4
          - host5
          - host6
          controller:
          - host1
          - host2
          - host3
          - host11
          - host12
          - host13
      

      然后创建组

          - add_host:
              name: "{{ item.1 }}"
              groups: "{{ item.0.key }}"
            with_subelements:
              - "{{ _groups|dict2items }}"
              - value
          - debug:
              var: groups
      

      给予

        groups:
          all:
          - host1
          - host2
          - host3
          - host4
          - host5
          - host6
          - host11
          - host12
          - host13
          cluster_one:
          - host1
          - host2
          - host3
          - host4
          - host5
          - host6
          cluster_two:
          - host11
          - host12
          - host13
          compute:
          - host4
          - host5
          - host6
          controller:
          - host1
          - host2
          - host3
          - host11
          - host12
          - host13
          ungrouped: []
      

      【讨论】:

        猜你喜欢
        • 2019-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-04
        • 1970-01-01
        • 1970-01-01
        • 2018-08-22
        • 1970-01-01
        相关资源
        最近更新 更多