我已经使用 Ansible 好几年了,但我一直在努力解决以下主题。
让我举一个简单的例子。我编写了一个角色来处理安装包。有时需要在主机级别(packages_installhost变量)定义应安装哪些软件包,其他时候则应在组级别定义。然而主机可以属于多个组,那么 Ansible 的概念是什么?我确信,Ansible 对于这种日常需求根本没有概念。
以前,我只是多次定义基于组的变量,并让 Ansible 合并它,但该方法不久前已被弃用(hash_behaviour=merge)。这让我有点震惊,因为这是我能想到的最直观的方法。
从那时起,我根据他们的组成员身份构建了逻辑来合并角色中的字典/列表。这确实有效,但(至少)还剩下两个问题:
最终我希望拥有灵活性和力量,有意义。我的角色的用户应该能够定义变量,引用我的角色,然后就高兴了。我确信,当用户觉得需要在他的剧本中嵌入额外的逻辑时,我的角色还不够好。
下面介绍的解决方案是为了解决我们的用例而创建的,该用例与您的用例非常匹配。它只需要在变量命名方面进行一些训练。让我们以您的示例为例,其中各个主机组、主机以及可能的角色默认值都希望安装一些软件包。在每个适当的位置定义一个列表变量,并使用相同的前缀命名所有变量,但使用每个定义它们的位置唯一的后缀。如果使用前缀
packages_
,那么您最终可能会得到 packages_myhost
、packages_group_a
、packages_group_b
、packages_group_q
、packages_role_foo_defaults
和 packages_role_bar_defaults
。可能还有更多;这些可以说是 myhost
可见的。
这些变量都不需要相互“了解”。但是,您需要确保它们具有足够独特的后缀才能使该技术发挥作用。他们在实际安装软件包的任务中聚集在一起。在那里,您可以使用诸如 mergevars 查找插件之类的东西合并列表:
"{{ lookup('mergevars', regex='^packages_.*') }}"
除了可选的正则表达式之外,
mergevars
还将采用变量名称,并按列出的顺序合并。任何名称也匹配 regex
的显式列出的变量将仅合并一次。通过 regex
选择的变量将合并在明确列出的变量之后,并按名称字母顺序排列。
"{{ lookup('mergevars', 'alpha_z', 'alpha_y', regex='^alpha_.*' }}"
mergevars
也不限于列表。如果你的变量是字典,它会像 combine
过滤器一样合并它们。只要确保所有变量的“形状”都相同:所有列表或所有字典。
您也不限于变量名称。您可以传入结构化数据,或按值(即不带引号)而不是按名称传入变量。但在这种情况下,匹配相同变量的
regex
不会注意到它已经包含在内,并且会合并它两次,所以要小心!
"{{ lookup('mergevars', {'a': 3}, beta_dict, {'z': 99}, regex='^alpha_dicts_.*' }}"
至少有一个
-v
,mergevars
将记录其合并的变量的顺序和名称。还有一个 dedup
选项用于删除结果列表的重复项,以及一个 recursive
选项用于深度合并字典,这两个选项都默认为 true
。 (所以你不必担心 group_vars 和 host_vars 文件都请求一些相同的包。)