6

我在我的角色中使用了很多 YAML 锚点和引用来将逻辑保持在一个位置,而不是在多个任务中重复自己。以下是一个非常非常基本的示例。

- &sometask
  name: "Some Task"
  some_module: with a lot of parameters
  with_items: list_A

- <<: *sometask
  name: "Some OTHER Task"
  with_items: list_B

这个例子可能没有显示这实际上是如何有用的,但它确实有用。想象一下,你遍历一个字典列表,将每个字典的各种键传递给模块,可能有相当复杂的“when”、“failed_when”和“changed_when”条件。你只是想干。

因此,我没有将整个任务定义两次,而是使用第一个锚点并将其所有内容合并到一个新任务中,然后覆盖不同的部分。这很好用。

需要明确的是,这是基本的 YAML 功能,与 Ansible 本身无关。

上述定义的结果(以及 Ansible 在解析 YAML 文件时看到的内容)将评估为:

- name: "Some Task"
  some_module: with a lot of parameters
  with_items: list_A

- name: "Some Task"
  some_module: with a lot of parameters
  with_items: list_A
  name: "Some OTHER Task"
  with_items: list_B

Ansible 2 现在具有在任务中多次定义键时抱怨的功能。它仍然有效,但在运行 playbook 时会产生不必要的噪音:

TASK [Some OTHER Task] *******************************************************
 [WARNING]: While constructing a mapping from /some/file.yml, line 42, column 3, found a duplicate dict key (name).  Using last defined value only.

 [WARNING]: While constructing a mapping from /some/file.yml, line 42, column 3, found a duplicate dict key (with_items).  Using last defined value only.

Ansible 配置允许防止deprecation_warningscommand_warnings. 有没有办法也可以防止这种警告?

4

4 回答 4

10

来晚了,我将不同意其他答案并支持 YAML 合并。剧本布局是高度主观的,最适合您的取决于您需要描述的配置。

是的,ansible 具有类似合并的功能,包括 include或 with_items / with_dict循环

我发现 YAML 合并的用例是任务只有几个异常值,因此可以覆盖的默认值是最紧凑和可读的表示。ansible 抱怨完全有效的语法令人沮丧。

相关 ansible 代码中的注释表明 The Devs Know Better than the users。

其中大部分来自 yaml.constructor.SafeConstructor。我们在这里复制它,以便我们可以在用户有重复的 dict 键时警告用户(pyyaml 静默允许覆盖键)

PyYAML 默默地允许“覆盖”键,因为键优先级在YAML 标准中明确处理。

于 2016-09-26T21:26:22.273 回答
6

从 Ansible 2.9.0 开始,这可以通过将ANSIBLE_DUPLICATE_YAML_DICT_KEY环境变量设置为ignore. 此变量的其他可能值是warn,这是默认值并保留原始行为,以及error,这会使 playbook 执行失败。

有关实施的详细信息,请参阅拉取请求。

于 2019-11-29T14:51:03.410 回答
0

还有一个system_warnings配置选项,但这些都不会使您看到的输出静音。

这是生成该消息的代码 ansible/lib/ansible/parsing/yaml/constructor.py

if key in mapping:
    display.warning('While constructing a mapping from {1}, line {2}, column {3}, found a duplicate dict key ({0}).  Using last defined value only.'.format(key, *mapping.ansible_pos))

虽然您对 YAML 引用的使用非常聪明,但我怀疑这会很快改变,因为 Ansible 的核心租户是剧本和任务的人类可读性。将有助于重复任务条件,尽管目前它们似乎仅限于剧本中的任务。

您总是可以提交一个拉取请求,添加一个禁用这些警告的选项并查看它的去向。

于 2016-02-03T13:14:12.413 回答
0

要在 Ansible 中的任务级别创建可重用功能,您应该查看任务包含。任务包含将允许您更自由地执行诸如使用 with_items 进行迭代等操作。在我的雇主中,我们自由地使用锚点/引用,但仅用于变量。鉴于在 Ansible 中创建可重用任务的几种现有方法,例如任务包含、剧本包含和角色,我们不需要像您描述的那样对任务使用锚/引用。

如果您只想在任务之间复制模块参数,您可以走模板路线:

args_for_case_x: arg1='some value' arg2=42 arg3='value3'

- name: a task of case x for a particular scenario
  the_module: "{{ args_for_case_x }}"
  when: condition_a

- name: a different use of case x
  the_module: "{{ args_for_case_x }}"
  when: condition_b

正如您所看到的,这并不容易支持基于循环迭代来改变参数,如果您使用上述重用功能之一,您可以获得这些参数。

于 2016-09-14T16:12:33.583 回答