Reputation: 59989
I use a lot of YAML anchors and references in my roles to keep the logic in a single spot instead of repeating myself in multiple tasks. Following is a very very basic example.
- &sometask
name: "Some Task"
some_module: with a lot of parameters
with_items: list_A
- <<: *sometask
name: "Some OTHER Task"
with_items: list_B
This example might not show how this is actually useful, but it is. Imagine you loop over a list of dicts, passing various keys from each dict to the module, maybe having quite complex "when", "failed_when" and "changed_when" conditions. You simply want to DRY.
So instead of defining the whole task twice, I use an anchor to the first one and merge all its content into a new task, then override the differing pieces. That works fine.
Just to be clear, this is basic YAML functionality and has nothing to do with Ansible itself.
The result of above definition (and what Ansible sees when it parsed the YAML file) would evaluate to:
- 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 now has a feature to complain when keys have been defined multiple times in a task. It still works, but creates unwanted noise when running the 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 configuration allows to prevent deprecation_warnings
and command_warnings
. Is there a way to also prevent this kind of warning?
Upvotes: 7
Views: 14802
Reputation: 8239
As of Ansible 2.9.0, this can be achieved by setting the ANSIBLE_DUPLICATE_YAML_DICT_KEY
environment variable to ignore
. Other possible values for this variable are warn
, which is the default and preserves the original behaviour, and error
, which makes the playbook execution fail.
See this pull request for details about the implementation.
Upvotes: 6
Reputation: 5592
Coming in late here I'm going to disagree with the other answers and endorse YAML merge. Playbook layout is highly subjective and what's best for you depends on the config you need to describe.
Yes, ansible has merge-like functionality with includes or with_items / with_dict loops.
The use case I've found for YAML merge is where tasks have only a few outliers, therefore a default value which can be overridden is the most compact and readable representation. Having ansible complain about perfectly valid syntax is frustrating.
The comment in the relevant ansible code suggests The Devs Know Better than the users.
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 silently allows "overwriting" keys because key precedence is explicitly dealt with in the YAML standard.
Upvotes: 10
Reputation: 21
To create reusable functionality at the task level in Ansible you should look into task includes. Task includes will allow you more freedom to do things like iterate using with_items, etc. At my employer we use anchors/references liberally, but only for variables. Given several existing ways of creating reusable tasks in Ansible such as task includes, playbook includes, and roles we have no need to use anchors/references for tasks the way you have described.
If you just want the module args to be copied between tasks you could go the templating route:
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
As you can see though, this doesn't easily support varying the args based on loop iteration which you could get if you used one of the aforementioned reuse features.
Upvotes: 0
Reputation: 2613
There is also a system_warnings
configuration option, but none of these will silence that output you're seeing.
Here is the code generating that message from
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))
While your use of YAML references is quite clever I doubt this is going to change anytime soon as a core tenant of Ansible is the human readability of the playbooks and tasks. Blocks will help with the repetition of conditionals on tasks, although they seem to be limited to tasks within a playbook at this time..
You could always submit a pull request adding an option for disabling these warnings and see where it goes.
Upvotes: 0