diff --git a/lib/ansible/modules/inventory/group_by.py b/lib/ansible/modules/inventory/group_by.py index 73e67625d7..7ee640c594 100644 --- a/lib/ansible/modules/inventory/group_by.py +++ b/lib/ansible/modules/inventory/group_by.py @@ -33,6 +33,12 @@ options: description: - The variables whose values will be used as groups required: true + parents: + description: + - The list of the parent groups + required: false + default: "all" + version_added: "2.4" author: "Jeroen Hoekx (@jhoekx)" notes: - Spaces in group names are converted to dashes '-'. @@ -47,4 +53,11 @@ EXAMPLES = ''' # Create groups like 'kvm-host' - group_by: key: virt_{{ ansible_virtualization_type }}_{{ ansible_virtualization_role }} + +# Create nested groups +- group_by: + key: el{{ ansible_distribution_major_version }}-{{ ansible_architecture }} + parents: + - el{{ ansible_distribution_major_version }} + ''' diff --git a/lib/ansible/plugins/action/group_by.py b/lib/ansible/plugins/action/group_by.py index 8f2f6e3626..1266803a59 100644 --- a/lib/ansible/plugins/action/group_by.py +++ b/lib/ansible/plugins/action/group_by.py @@ -18,6 +18,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from ansible.plugins.action import ActionBase +from ansible.module_utils.six import string_types class ActionModule(ActionBase): @@ -38,8 +39,11 @@ class ActionModule(ActionBase): return result group_name = self._task.args.get('key') - group_name = group_name.replace(' ', '-') + parent_groups = self._task.args.get('parents', ['all']) + if isinstance(parent_groups, string_types): + parent_groups = [parent_groups] result['changed'] = False - result['add_group'] = group_name + result['add_group'] = group_name.replace(' ', '-') + result['parent_groups'] = [name.replace(' ', '-') for name in parent_groups] return result diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index ea8a94ea59..efb60c53af 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -632,12 +632,17 @@ class StrategyBase: # host object from the master inventory real_host = self._inventory.hosts[host.name] group_name = result_item.get('add_group') + parent_group_names = result_item.get('parent_groups', []) - if group_name not in self._inventory.groups: - # create the new group and add it to inventory - self._inventory.add_group(group_name) - changed = True + for name in [group_name] + parent_group_names: + if name not in self._inventory.groups: + # create the new group and add it to inventory + self._inventory.add_group(name) + changed = True group = self._inventory.groups[group_name] + for parent_group_name in parent_group_names: + parent_group = self._inventory.groups[parent_group_name] + parent_group.add_child_group(group) if real_host.name not in group.get_hosts(): group.add_host(real_host) diff --git a/test/integration/targets/group_by/test_group_by.yml b/test/integration/targets/group_by/test_group_by.yml index 21f76bcb22..3d439c6a09 100644 --- a/test/integration/targets/group_by/test_group_by.yml +++ b/test/integration/targets/group_by/test_group_by.yml @@ -185,3 +185,21 @@ tasks: - name: check group_vars variable overrides for camelus assert: { that: ["uno == 1", "dos == 'two'", "tres == 3"] } + +- name: Nested group validation + hosts: lama + gather_facts: false + tasks: + - name: group by genus with parent + group_by: key=vicugna-{{ genus }} parents=vicugna + - name: check group_vars variable overrides for vicugna-lama + assert: { that: ["uno == 1", "dos == 2", "tres == 'three'"] } + + - name: group by genus with nonexistent parent + group_by: + key: "{{ genus }}" + parents: + - oxydactylus + - stenomylus + - name: check parent groups + assert: { that: ["'oxydactylus' in group_names", "'stenomylus' in group_names"] }