Ansible 中的 Puppet hiera 等价物

Puppet hiera equivalent in Ansible

hiera.yaml

---
:hierarchy:
- node/%{host_fqdn}
  - site_config/%{host_site_name}
  - site_config/perf_%{host_performance_class}
  - site_config/%{host_type}_v%{host_type_version}
  - site/%{host_site_name}
  - environments/%{site_environment}
  - types/%{host_type}_v%{host_type_version}
  - hosts
  - sites
  - users
  - common
# options are native, deep, deeper
:merge_behavior: deeper

我们目前有这个 hiera 配置。因此,配置按以下顺序合并 common.yaml > users.yaml > sites.yaml > hosts.yaml > types/xxx_vxxx.yaml > 等。对于可变顶层层次结构,它仅当该文件存在时才会被覆盖。

例如: common.yaml

server:
  instance_type: m3.medium

site_config/mysite.yaml

server:
  instance_type: m4.large

因此对于所有其他站点,实例类型将为 m3.medium,但仅对于 mysite 为 m4.large。

如何在 Ansible 中实现相同的功能?

我对 Puppet 不熟悉,所以这可能不是直接映射。但我理解你的问题是 "how do I use values in one shared location but override their definitions for different servers?"。在 Ansible 中,您可以使用 variables.

你可以define variables directly in your inventory. You can define variables in host- and group-specific files. You can define variables at a playbook level. You can define variables at a role level. Heck, you can even define variables with command-line switches.

在所有这些地方之间,您应该能够定义覆盖以适合您的情况。您可能需要查看 the documentation section on how to decide where to define a variable 了解更多信息。

我认为@Xiong 是正确的,你应该在 Ansible 中采用变量方式。
您可以使用从一般到特定的变量优先级设置灵活的清单。

但如果有帮助,您可以试试这个片段:

---
- hosts: loc-test
  tasks:
    - include_vars: hiera/{{ item }}
      with_items:
        - common.yml
        - "node/{{ ansible_fqdn }}/users.yml"
        - "node/{{ ansible_fqdn }}/sites.yml"
        - "node/{{ ansible_fqdn }}/types/{{ host_type }}_v{{ host_type_version }}.yml"
      failed_when: false

    - debug: var=server

这将尝试从结构与您的问题相似的文件中加载变量。
不存在的文件将被忽略(因为 failed_when: false)。
文件按此列表的顺序加载(从上到下),覆盖以前的值。

陷阱:

  • 您在列表中使用的所有变量都必须定义(例如本例中的 host_type 不能在 common.yml 中定义),因为要迭代的项目列表在执行整个循环之前进行模板化(请参阅解决方法的更新)。

  • Ansible 默认覆盖(替换)指令,我猜你的用例需要合并行为。这可以通过 hash_behavior 设置来实现——但这对于 Ansible 剧本来说是不常见的。

P.S. 您可以通过将 with_items 更改为 with_first_found 并反转列表来改变从上到下的合并行为(从具体到一般)。在这种情况下,Ansible 将从找到的第一个文件加载变量。

更新: 使用先前包含在文件路径中的变量。

您可以将循环拆分为多个任务,这样 Ansible 将在模板化下一个文件的包含路径之前评估每个任务的结果。
制作 hiera_inc.yml:

- include_vars: hiera/common.yml
  failed_when: false
- include_vars: hiera/node/{{ ansible_fqdn }}/users.yml
  failed_when: false
- include_vars: hiera/node/{{ ansible_fqdn }}/sites.yml
  failed_when: false
- include_vars: hiera/node/{{ ansible_fqdn }}/types/{{ host_type | default('none') }}_v{{ host_type_version | default('none') }}.yml
  failed_when: false

在你的主要剧本中:

- include: hiera_inc.yml

这看起来有点笨拙,但这样您就可以在 common.yaml 中定义 host_type,它将在下一个任务的路径模板中得到尊重。

使用 Ansible 2.2 可以将 include_vars 转换为命名变量(不是全局主机 space),因此您可以将 include_vars 转换为 hiera_facts 并使用 combine 过滤以在不改变全局哈希行为的情况下合并它们。

它看起来比 Hiera 更基础一些,但有人已经创建了一个具有类似语法的基本 ansible 查找插件

https://github.com/sailthru/ansible-oss/tree/master/tools/echelon