mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-03-21 20:59:10 +00:00
* merge_variables: extended merge capabilities added This extension gives you more control over the variable merging process of the lookup plugin `merge_variables`. It closes the gap between Puppet's Hiera merging capabilities and the limitations of Ansible's default variable plugin `host_group_vars` regarding fragment-based value definition. You can now decide which merge strategy should be applied to dicts, lists, and other types. Furthermore, you can specify a merge strategy that should be applied in case of type conflicts. The default behavior of the plugin has been preserved so that it is fully backward-compatible with the already implemented state. Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Update changelogs/fragments/11536-merge-variables-extended-merging-capabilities.yml Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/lookup/merge_variables.py Co-authored-by: Felix Fontein <felix@fontein.de> * Periods added at the end of each choice description Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Update plugins/lookup/merge_variables.py Co-authored-by: Mark <40321020+m-a-r-k-e@users.noreply.github.com> * ref: follow project standard for choice descriptions Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * ref: more examples added and refactoring Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Update plugins/lookup/merge_variables.py Co-authored-by: Felix Fontein <felix@fontein.de> * ref: some more comments to examples added Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * fix: unused import removed Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * ref: re-add "merge" to strategy map Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Update comments Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Specification of transformations solely as string Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Comments updated Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * ref: `append_rp` and `prepend_rp` removed feat: options dict for list transformations re-added feat: allow setting `keep` for dedup transformation with possible values: `first` (default) and `last` Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * ref: improve options documentation Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * ref: documentation improved, avoiding words like newer or older in merge description Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * Update plugins/lookup/merge_variables.py Co-authored-by: Felix Fontein <felix@fontein.de> * ref: "prio" replaced by "dict" Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> * feat: two integration tests added Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> --------- Signed-off-by: Fiehe Christoph <c.fiehe@eurodata.de> Co-authored-by: Fiehe Christoph <c.fiehe@eurodata.de> Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Mark <40321020+m-a-r-k-e@users.noreply.github.com>
230 lines
8 KiB
YAML
230 lines
8 KiB
YAML
---
|
|
# Copyright (c) 2020, Thales Netherlands
|
|
# Copyright (c) 2021, Ansible Project
|
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
- name: Test merge_variables lookup plugin
|
|
hosts: localhost
|
|
tasks:
|
|
- name: Include test data
|
|
include_vars: vars.yml
|
|
|
|
# Test the default behavior
|
|
- name: Test merge list
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_list }}"
|
|
|
|
- name: Validate that the list is complete
|
|
assert:
|
|
that:
|
|
- "(merged_list | length) == 2"
|
|
- "'item1' in merged_list"
|
|
- "'item3' in merged_list"
|
|
vars:
|
|
merged_list: "{{ lookup('community.general.merge_variables', '^.+__merge_list$') }}"
|
|
|
|
- name: Test merge dict
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_dict }}"
|
|
|
|
- name: Validate that dict is complete
|
|
assert:
|
|
that:
|
|
- "'item1' in merged_dict"
|
|
- "'item2' in merged_dict"
|
|
- "'list_item' in merged_dict"
|
|
- "(merged_dict.list_item | length) == 2"
|
|
- "'test1' in (merged_dict.list_item)"
|
|
- "'test2' in (merged_dict.list_item)"
|
|
vars:
|
|
merged_dict: "{{ lookup('community.general.merge_variables', '^.+__merge_dict$') }}"
|
|
|
|
- name: Test shallow dict merge with 'list_merge=append' and 'dedup'
|
|
block:
|
|
- name: Print the merged dict
|
|
ansible.builtin.debug:
|
|
msg: "{{ merged_dict }}"
|
|
|
|
- name: Validate the merged dict
|
|
ansible.builtin.assert:
|
|
that: "merged_dict == expected_dict"
|
|
vars:
|
|
expected_dict:
|
|
a: "{{ testdict4__test['a'] }}"
|
|
b:
|
|
- 3
|
|
- 4
|
|
- "5": value
|
|
- 1
|
|
- 2
|
|
vars:
|
|
merged_dict: "{{
|
|
lookup(
|
|
'community.general.merge_variables', '__test', pattern_type='suffix', override='ignore',
|
|
dict_merge='shallow', list_merge='prepend', list_transformations=['dedup']) }}"
|
|
|
|
- name: Test deep dict merge with 'list_merge=prepend' and 'dedup' with 'keep=last'
|
|
block:
|
|
- name: Print the merged dict
|
|
ansible.builtin.debug:
|
|
msg: "{{ merged_dict }}"
|
|
|
|
- name: Validate the merged dict
|
|
ansible.builtin.assert:
|
|
that: "merged_dict == expected_dict"
|
|
vars:
|
|
expected_dict:
|
|
a:
|
|
a:
|
|
x: low_value
|
|
y: high_value
|
|
list:
|
|
- high_value
|
|
- low_value
|
|
z: high_value
|
|
b:
|
|
- 4
|
|
- "5": value
|
|
- 1
|
|
- 2
|
|
- 3
|
|
vars:
|
|
merged_dict: "{{
|
|
lookup(
|
|
'community.general.merge_variables', '__test', pattern_type='suffix', override='ignore',
|
|
dict_merge='deep', list_merge='prepend',
|
|
list_transformations=[{'name': 'dedup', 'options': {'keep': 'last'}}]) }}"
|
|
|
|
# Test the behavior when no results are found
|
|
- name: Test merge without results
|
|
block:
|
|
- debug:
|
|
msg: "{{ not_found }}"
|
|
- name: Validate that the variable defaults to an empty list
|
|
vars:
|
|
assert:
|
|
that:
|
|
- "(not_found | default('default-used', True)) == 'default-used'"
|
|
vars:
|
|
not_found: "{{ lookup('community.general.merge_variables', '^.+__merge_not_found$') }}"
|
|
|
|
# Test the 'pattern_type' options
|
|
- name: Test merge list (pattern_type = prefix)
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_list }}"
|
|
|
|
- name: Validate that the list is complete
|
|
assert:
|
|
that:
|
|
- "(merged_list | length) == 4"
|
|
- "'item1' in merged_list"
|
|
- "'item2' in merged_list"
|
|
- "'item2' in merged_list"
|
|
- "'item3' in merged_list"
|
|
vars:
|
|
merged_list: "{{ lookup('community.general.merge_variables', 'testlist', pattern_type='prefix') }}"
|
|
|
|
- name: Test merge list (pattern_type = suffix)
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_list }}"
|
|
|
|
- name: Validate that the list is complete
|
|
assert:
|
|
that:
|
|
- "(merged_list | length) == 2"
|
|
- "'item1' in merged_list"
|
|
- "'item3' in merged_list"
|
|
vars:
|
|
merged_list: "{{ lookup('community.general.merge_variables', '__merge_list', pattern_type='suffix') }}"
|
|
|
|
- name: Test merge list (pattern_type = regex)
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_list }}"
|
|
|
|
- name: Validate that the list is complete
|
|
assert:
|
|
that:
|
|
- "(merged_list | length) == 3"
|
|
- "'item1' in merged_list"
|
|
- "'item2' in merged_list"
|
|
- "'item3' in merged_list"
|
|
vars:
|
|
merged_list: "{{ lookup('community.general.merge_variables', '^testlist[0-9].*', pattern_type='regex') }}"
|
|
|
|
# Test the 'initial_value' option
|
|
- name: Test merge without results but with initial value
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ not_found_initial_value }}"
|
|
|
|
- name: Validate that the variable only contains the initial value
|
|
vars:
|
|
assert:
|
|
that:
|
|
- "(not_found_initial_value | count) == 1"
|
|
- "(not_found_initial_value | first) == 'item2'"
|
|
vars:
|
|
not_found_initial_value: "{{ lookup('community.general.merge_variables', '^.+__merge_not_found$', initial_value=testlist_initial_value) }}"
|
|
|
|
- name: Test merging a list with an initial value
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_list_with_initial_value }}"
|
|
|
|
- name: Validate that the list is complete
|
|
assert:
|
|
that:
|
|
- "(merged_list_with_initial_value | length) == 3"
|
|
- "'item1' in merged_list_with_initial_value"
|
|
- "'item2' in merged_list_with_initial_value"
|
|
- "'item3' in merged_list_with_initial_value"
|
|
vars:
|
|
merged_list_with_initial_value: "{{ lookup('community.general.merge_variables', '^.+__merge_list$', initial_value=testlist_initial_value) }}"
|
|
|
|
# Test the 'override' options
|
|
- name: Test the 'override=warn' option
|
|
block:
|
|
- name: Print the merged list
|
|
debug:
|
|
msg: "{{ merged_with_override_warn }}"
|
|
|
|
- name: Validate that the dict is complete and the warning is printed
|
|
assert:
|
|
that:
|
|
- "'key_to_override' in merged_with_override_warn"
|
|
- "merged_with_override_warn.key_to_override == 'Override value'"
|
|
- "'key_to_override' in lookup('file', logging_output_file)" # Check if a message is given
|
|
- "'[WARNING]' in lookup('file', logging_output_file)" # and verify that the message is a WARNING
|
|
vars:
|
|
merged_with_override_warn: "{{ lookup('community.general.merge_variables', '^.+__override_warn$', initial_value=override_warn_init, override='warn') }}"
|
|
|
|
- name: Test the 'override=error' option
|
|
block:
|
|
- name: Validate that an override result in an error
|
|
debug:
|
|
msg: "{{ lookup('community.general.merge_variables', '^.+__override_error$', initial_value=override_error_init, override='error') }}"
|
|
ignore_errors: true # Do not stop the playbook
|
|
register: _override_error_result
|
|
|
|
- name: Print the output
|
|
debug:
|
|
msg: "{{ _override_error_result }}"
|
|
|
|
- name: Validate that the error is reported
|
|
assert:
|
|
that:
|
|
- "_override_error_result.failed"
|
|
- "'key_to_override' in _override_error_result.msg"
|