diff --git a/changelogs/fragments/60882-keyed_groups-leading-separator-toggle.yaml b/changelogs/fragments/60882-keyed_groups-leading-separator-toggle.yaml new file mode 100644 index 00000000000..ed23ed506ab --- /dev/null +++ b/changelogs/fragments/60882-keyed_groups-leading-separator-toggle.yaml @@ -0,0 +1,2 @@ +minor_changes: + - constructed - Add a toggle to allow the separator to be omitted if no prefix has been provided. diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 8e134cb8d9f..1e73de70141 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -39,4 +39,15 @@ options: key: use_extra_vars env: - name: ANSIBLE_INVENTORY_USE_EXTRA_VARS + leading_separator: + description: + - Use in conjunction with keyed_groups. + - By default, a keyed group that does not have a prefix or a separator provided will have a name that starts with an underscore. + - This is because the default prefix is "" and the default separator is "_". + - Set this option to False to omit the leading underscore (or other separator) if no prefix is given. + - If the group name is derived from a mapping the separator is still used to concatenate the items. + - To not use a separator in the group name at all, set the separator for the keyed group to an empty string instead. + type: boolean + default: True + version_added: '2.11' ''' diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index 27e3c5d485d..e0e334e40a9 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -443,6 +443,8 @@ class Constructable(object): raise AnsibleParserError("Invalid group name format, expected a string or a list of them or dictionary, got: %s" % type(key)) for bare_name in new_raw_group_names: + if prefix == '' and self.get_option('leading_separator') is False: + sep = '' gname = self._sanitize_group_name('%s%s%s' % (prefix, sep, bare_name)) result_gname = self.inventory.add_group(gname) self.inventory.add_host(host, result_gname) diff --git a/test/integration/targets/inventory_constructed/aliases b/test/integration/targets/inventory_constructed/aliases new file mode 100644 index 00000000000..b59832142f2 --- /dev/null +++ b/test/integration/targets/inventory_constructed/aliases @@ -0,0 +1 @@ +shippable/posix/group3 diff --git a/test/integration/targets/inventory_constructed/constructed.yml b/test/integration/targets/inventory_constructed/constructed.yml new file mode 100644 index 00000000000..baeea323f7b --- /dev/null +++ b/test/integration/targets/inventory_constructed/constructed.yml @@ -0,0 +1,19 @@ +plugin: constructed +keyed_groups: + - key: hostvar0 + - key: hostvar1 + - key: hostvar2 + + - key: hostvar0 + separator: 'separator' + - key: hostvar1 + separator: 'separator' + - key: hostvar2 + separator: 'separator' + + - key: hostvar0 + prefix: 'prefix' + - key: hostvar1 + prefix: 'prefix' + - key: hostvar2 + prefix: 'prefix' diff --git a/test/integration/targets/inventory_constructed/no_leading_separator_constructed.yml b/test/integration/targets/inventory_constructed/no_leading_separator_constructed.yml new file mode 100644 index 00000000000..5f35de14088 --- /dev/null +++ b/test/integration/targets/inventory_constructed/no_leading_separator_constructed.yml @@ -0,0 +1,20 @@ +plugin: constructed +keyed_groups: + - key: hostvar0 + - key: hostvar1 + - key: hostvar2 + + - key: hostvar0 + separator: 'separator' + - key: hostvar1 + separator: 'separator' + - key: hostvar2 + separator: 'separator' + + - key: hostvar0 + prefix: 'prefix' + - key: hostvar1 + prefix: 'prefix' + - key: hostvar2 + prefix: 'prefix' +leading_separator: False diff --git a/test/integration/targets/inventory_constructed/runme.sh b/test/integration/targets/inventory_constructed/runme.sh new file mode 100755 index 00000000000..7a36be017e7 --- /dev/null +++ b/test/integration/targets/inventory_constructed/runme.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -ex + +ansible-inventory -i static_inventory.yml -i constructed.yml --graph | tee out.txt + +grep '@_hostvalue1' out.txt +grep '@_item0' out.txt +grep '@_key0_value0' out.txt +grep '@prefix_hostvalue1' out.txt +grep '@prefix_item0' out.txt +grep '@prefix_key0_value0' out.txt +grep '@separatorhostvalue1' out.txt +grep '@separatoritem0' out.txt +grep '@separatorkey0separatorvalue0' out.txt + +ansible-inventory -i static_inventory.yml -i no_leading_separator_constructed.yml --graph | tee out.txt + +grep '@hostvalue1' out.txt +grep '@item0' out.txt +grep '@key0_value0' out.txt +grep '@key0separatorvalue0' out.txt +grep '@prefix_hostvalue1' out.txt +grep '@prefix_item0' out.txt +grep '@prefix_key0_value0' out.txt diff --git a/test/integration/targets/inventory_constructed/static_inventory.yml b/test/integration/targets/inventory_constructed/static_inventory.yml new file mode 100644 index 00000000000..d050df4f42e --- /dev/null +++ b/test/integration/targets/inventory_constructed/static_inventory.yml @@ -0,0 +1,8 @@ +all: + hosts: + host0: + hostvar0: + key0: value0 + hostvar1: hostvalue1 + hostvar2: + - item0 diff --git a/test/units/plugins/inventory/test_constructed.py b/test/units/plugins/inventory/test_constructed.py index 6d521982a0a..d12468d0096 100644 --- a/test/units/plugins/inventory/test_constructed.py +++ b/test/units/plugins/inventory/test_constructed.py @@ -33,6 +33,7 @@ def inventory_module(): r = InventoryModule() r.inventory = InventoryData() r.templar = Templar(None) + r._options = {'leading_separator': True} return r