防止 Ansible 2 中的重复键警告

Prevent duplicate key warnings in Ansible 2

我在我的角色中使用了很多 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 现在具有在任务中多次定义键时发出警告的功能。它仍然有效,但在 运行 剧本时会产生不必要的噪音:

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_warnings and command_warnings。有没有办法也防止这种警告?

还有一个 system_warnings 配置选项,但其中 none 将使您看到的输出静音。

这是生成该消息的代码 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 的核心租户是剧本和任务的人类可读性。 Blocks 将有助于重复任务条件,尽管此时它们似乎仅限于剧本中的任务。

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

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

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

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

不过如您所见,这并不容易支持根据循环迭代来改变参数,如果您使用上述重用功能之一,您可以获得。

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

是的,ansible 具有与 includes or with_items / with_dict loops.

类似的合并功能

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

relevant ansible code 中的评论表明开发者比用户更了解。

Most of this is from yaml.constructor.SafeConstructor. We replicate it here so that we can warn users when they have duplicate dict keys (pyyaml silently allows overwriting keys)

PyYAML 静默允许 "overwriting" 键,因为键优先级在 the YAML standard.

中明确处理

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

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