mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Update VirtualBox Group parsing to align with documentation. (#8510)
* Update VirtualBox Group parsing to align with documentation. Previously, we could separate the group string on the `/` char and consider each element to be distinct, top-level groups. This change implements the notion of nested groups and the use of the `,` char to split multiple groups. * Address code review comments. Changed the implementation from a breaking change to a minor change by introducing a new parameter to configure the behaviour. Keep the default values to maintain the existing behaviour, and allow consumers an option to opt-in. * Fix line length. The long lines were tripping CI. Reduce the length. * Apply suggestions from code review Update documentation to match expected conventions and correct the final rendered formatting. Set the initial parent_group to `None` instead of `all` and rely on the parent class' inventory reconciliation logic to ensure consistent behaviour across different inventory plugins. Co-authored-by: Felix Fontein <felix@fontein.de> * Reword module arg description to avoid issues with CI. One of the lines ended with a colon character which made the CI tests fail since it would interpret it as a YAML key. Reworded the description altogether to avoid that issue. * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
9f3103e891
commit
21b16c1c77
2 changed files with 80 additions and 8 deletions
3
changelogs/fragments/8508-virtualbox-inventory.yml
Normal file
3
changelogs/fragments/8508-virtualbox-inventory.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
minor_changes:
|
||||||
|
- >-
|
||||||
|
virtualbox inventory plugin - expose a new parameter ``enable_advanced_group_parsing`` to change how the VirtualBox dynamic inventory parses VM groups (https://github.com/ansible-collections/community.general/issues/8508, https://github.com/ansible-collections/community.general/pull/8510).
|
|
@ -14,6 +14,8 @@ DOCUMENTATION = '''
|
||||||
- Get inventory hosts from the local virtualbox installation.
|
- Get inventory hosts from the local virtualbox installation.
|
||||||
- Uses a YAML configuration file that ends with virtualbox.(yml|yaml) or vbox.(yml|yaml).
|
- Uses a YAML configuration file that ends with virtualbox.(yml|yaml) or vbox.(yml|yaml).
|
||||||
- The inventory_hostname is always the 'Name' of the virtualbox instance.
|
- The inventory_hostname is always the 'Name' of the virtualbox instance.
|
||||||
|
- Groups can be assigned to the VMs using C(VBoxManage). Multiple groups can be assigned by using V(/) as a delimeter.
|
||||||
|
- A separate parameter, O(enable_advanced_group_parsing) is exposed to change grouping behaviour. See the parameter documentation for details.
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- constructed
|
- constructed
|
||||||
- inventory_cache
|
- inventory_cache
|
||||||
|
@ -35,6 +37,19 @@ DOCUMENTATION = '''
|
||||||
description: create vars from virtualbox properties
|
description: create vars from virtualbox properties
|
||||||
type: dictionary
|
type: dictionary
|
||||||
default: {}
|
default: {}
|
||||||
|
enable_advanced_group_parsing:
|
||||||
|
description:
|
||||||
|
- The default group parsing rule (when this setting is set to V(false)) is to split the VirtualBox VM's group based on the V(/) character and
|
||||||
|
assign the resulting list elements as an Ansible Group.
|
||||||
|
- Setting O(enable_advanced_group_parsing=true) changes this behaviour to match VirtualBox's interpretation of groups according to
|
||||||
|
U(https://www.virtualbox.org/manual/UserManual.html#gui-vmgroups).
|
||||||
|
Groups are now split using the V(,) character, and the V(/) character indicates nested groups.
|
||||||
|
- When enabled, a VM that's been configured using V(VBoxManage modifyvm "vm01" --groups "/TestGroup/TestGroup2,/TestGroup3") will result in
|
||||||
|
the group C(TestGroup2) being a child group of C(TestGroup); and
|
||||||
|
the VM being a part of C(TestGroup2) and C(TestGroup3).
|
||||||
|
default: false
|
||||||
|
type: bool
|
||||||
|
version_added: 9.2.0
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -177,14 +192,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
|
|
||||||
# found groups
|
# found groups
|
||||||
elif k == 'Groups':
|
elif k == 'Groups':
|
||||||
for group in v.split('/'):
|
if self.get_option('enable_advanced_group_parsing'):
|
||||||
if group:
|
self._handle_vboxmanage_group_string(v, current_host, cacheable_results)
|
||||||
group = make_unsafe(group)
|
else:
|
||||||
group = self.inventory.add_group(group)
|
self._handle_group_string(v, current_host, cacheable_results)
|
||||||
self.inventory.add_child(group, current_host)
|
|
||||||
if group not in cacheable_results:
|
|
||||||
cacheable_results[group] = {'hosts': []}
|
|
||||||
cacheable_results[group]['hosts'].append(current_host)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -227,6 +238,64 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
|
|
||||||
return all(find_host(host, inventory))
|
return all(find_host(host, inventory))
|
||||||
|
|
||||||
|
def _handle_group_string(self, vboxmanage_group, current_host, cacheable_results):
|
||||||
|
'''Handles parsing the VM's Group assignment from VBoxManage according to this inventory's initial implementation.'''
|
||||||
|
# The original implementation of this inventory plugin treated `/` as
|
||||||
|
# a delimeter to split and use as Ansible Groups.
|
||||||
|
for group in vboxmanage_group.split('/'):
|
||||||
|
if group:
|
||||||
|
group = make_unsafe(group)
|
||||||
|
group = self.inventory.add_group(group)
|
||||||
|
self.inventory.add_child(group, current_host)
|
||||||
|
if group not in cacheable_results:
|
||||||
|
cacheable_results[group] = {'hosts': []}
|
||||||
|
cacheable_results[group]['hosts'].append(current_host)
|
||||||
|
|
||||||
|
def _handle_vboxmanage_group_string(self, vboxmanage_group, current_host, cacheable_results):
|
||||||
|
'''Handles parsing the VM's Group assignment from VBoxManage according to VirtualBox documentation.'''
|
||||||
|
# Per the VirtualBox documentation, a VM can be part of many groups,
|
||||||
|
# and it's possible to have nested groups.
|
||||||
|
# Many groups are separated by commas ",", and nested groups use
|
||||||
|
# slash "/".
|
||||||
|
# https://www.virtualbox.org/manual/UserManual.html#gui-vmgroups
|
||||||
|
# Multi groups: VBoxManage modifyvm "vm01" --groups "/TestGroup,/TestGroup2"
|
||||||
|
# Nested groups: VBoxManage modifyvm "vm01" --groups "/TestGroup/TestGroup2"
|
||||||
|
|
||||||
|
for group in vboxmanage_group.split(','):
|
||||||
|
if not group:
|
||||||
|
# We could get an empty element due how to split works, and
|
||||||
|
# possible assignments from VirtualBox. e.g. ,/Group1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if group == "/":
|
||||||
|
# This is the "root" group. We get here if the VM was not
|
||||||
|
# assigned to a particular group. Consider the host to be
|
||||||
|
# unassigned to a group.
|
||||||
|
continue
|
||||||
|
|
||||||
|
parent_group = None
|
||||||
|
for subgroup in group.split('/'):
|
||||||
|
if not subgroup:
|
||||||
|
# Similarly to above, we could get an empty element.
|
||||||
|
# e.g //Group1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if subgroup == '/':
|
||||||
|
# "root" group.
|
||||||
|
# Consider the host to be unassigned
|
||||||
|
continue
|
||||||
|
|
||||||
|
subgroup = make_unsafe(subgroup)
|
||||||
|
subgroup = self.inventory.add_group(subgroup)
|
||||||
|
if parent_group is not None:
|
||||||
|
self.inventory.add_child(parent_group, subgroup)
|
||||||
|
self.inventory.add_child(subgroup, current_host)
|
||||||
|
if subgroup not in cacheable_results:
|
||||||
|
cacheable_results[subgroup] = {'hosts': []}
|
||||||
|
cacheable_results[subgroup]['hosts'].append(current_host)
|
||||||
|
|
||||||
|
parent_group = subgroup
|
||||||
|
|
||||||
def verify_file(self, path):
|
def verify_file(self, path):
|
||||||
|
|
||||||
valid = False
|
valid = False
|
||||||
|
|
Loading…
Reference in a new issue