Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to proxmox dynamic inventory to exclude nodes #7461

Merged
merged 14 commits into from
Nov 26, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- proxmox inventory plugin - adds an option to exclude nodes from the dynamic inventory generation. The new setting is optional, not using this option will behave as usual (https://github.com/ansible-collections/community.general/issues/6714, https://github.com/ansible-collections/community.general/pull/7461).
24 changes: 15 additions & 9 deletions plugins/inventory/proxmox.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@
- The default of this option changed from V(true) to V(false) in community.general 6.0.0.
type: bool
default: false
exclude_nodes:
description: Exclude proxmox nodes and the nodes-group from the inventory output.
type: bool
default: false
IamLunchbox marked this conversation as resolved.
Show resolved Hide resolved
version_added: 8.1.0
filters:
version_added: 4.6.0
description: A list of Jinja templates that allow filtering hosts.
Expand Down Expand Up @@ -565,9 +570,9 @@ def _populate(self):

for group in default_groups:
self.inventory.add_group(self._group('all_%s' % (group)))

nodes_group = self._group('nodes')
self.inventory.add_group(nodes_group)
if not self.exclude_nodes:
self.inventory.add_group(nodes_group)

want_proxmox_nodes_ansible_host = self.get_option("want_proxmox_nodes_ansible_host")

Expand All @@ -577,22 +582,23 @@ def _populate(self):
for node in self._get_nodes():
if not node.get('node'):
continue

self.inventory.add_host(node['node'])
if node['type'] == 'node':
if not self.exclude_nodes:
felixfontein marked this conversation as resolved.
Show resolved Hide resolved
self.inventory.add_host(node['node'])
if node['type'] == 'node' and not self.exclude_nodes:
self.inventory.add_child(nodes_group, node['node'])

if node['status'] == 'offline':
continue

# get node IP address
if want_proxmox_nodes_ansible_host:
if want_proxmox_nodes_ansible_host and not self.exclude_nodes:
ip = self._get_node_ip(node['node'])
self.inventory.set_variable(node['node'], 'ansible_host', ip)

# Setting composite variables
variables = self.inventory.get_host(node['node']).get_vars()
self._set_composite_vars(self.get_option('compose'), variables, node['node'], strict=self.strict)
if not self.exclude_nodes:
variables = self.inventory.get_host(node['node']).get_vars()
self._set_composite_vars(self.get_option('compose'), variables, node['node'], strict=self.strict)

# add LXC/Qemu groups for the node
for ittype in ('lxc', 'qemu'):
Expand Down Expand Up @@ -635,8 +641,8 @@ def parse(self, inventory, loader, path, cache=True):

if self.get_option('qemu_extended_statuses') and not self.get_option('want_facts'):
raise AnsibleError('You must set want_facts to True if you want to use qemu_extended_statuses.')

# read rest of options
self.exclude_nodes = self.get_option('exclude_nodes')
self.cache_key = self.get_cache_key(path)
self.use_cache = cache and self.get_option('cache')
self.host_filters = self.get_option('filters')
Expand Down
45 changes: 43 additions & 2 deletions tests/unit/plugins/inventory/test_proxmox.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,13 +646,15 @@ def test_populate(inventory, mocker):
inventory.group_prefix = 'proxmox_'
inventory.facts_prefix = 'proxmox_'
inventory.strict = False
inventory.exclude_nodes = False

opts = {
'group_prefix': 'proxmox_',
'facts_prefix': 'proxmox_',
'want_facts': True,
'want_proxmox_nodes_ansible_host': True,
'qemu_extended_statuses': True
'qemu_extended_statuses': True,
'exclude_nodes': False
}

# bypass authentication and API fetch calls
Expand Down Expand Up @@ -723,13 +725,15 @@ def test_populate_missing_qemu_extended_groups(inventory, mocker):
inventory.group_prefix = 'proxmox_'
inventory.facts_prefix = 'proxmox_'
inventory.strict = False
inventory.exclude_nodes = False

opts = {
'group_prefix': 'proxmox_',
'facts_prefix': 'proxmox_',
'want_facts': True,
'want_proxmox_nodes_ansible_host': True,
'qemu_extended_statuses': False
'qemu_extended_statuses': False,
'exclude_nodes': False
}

# bypass authentication and API fetch calls
Expand All @@ -743,3 +747,40 @@ def test_populate_missing_qemu_extended_groups(inventory, mocker):
# make sure that ['prelaunch', 'paused'] are not in the group list
for group in ['paused', 'prelaunch']:
assert ('%sall_%s' % (inventory.group_prefix, group)) not in inventory.inventory.groups


def test_populate_exclude_nodes(inventory, mocker):
# module settings
inventory.proxmox_user = 'root@pam'
inventory.proxmox_password = 'password'
inventory.proxmox_url = 'https://localhost:8006'
inventory.group_prefix = 'proxmox_'
inventory.facts_prefix = 'proxmox_'
inventory.strict = False
inventory.exclude_nodes = True

opts = {
'group_prefix': 'proxmox_',
'facts_prefix': 'proxmox_',
'want_facts': True,
'want_proxmox_nodes_ansible_host': True,
'qemu_extended_statuses': False,
'exclude_nodes': True
}

# bypass authentication and API fetch calls
inventory._get_auth = mocker.MagicMock(side_effect=get_auth)
inventory._get_json = mocker.MagicMock(side_effect=get_json)
inventory._get_vm_snapshots = mocker.MagicMock(side_effect=get_vm_snapshots)
inventory.get_option = mocker.MagicMock(side_effect=get_option(opts))
inventory._can_add_host = mocker.MagicMock(return_value=True)
inventory._populate()

# make sure that nodes are not in the inventory
for node in ['testnode', 'testnode2']:
assert node not in inventory.inventory.hosts
# make sure that nodes group is absent
assert ('%s_nodes' % (inventory.group_prefix)) not in inventory.inventory.groups
# make sure that nodes are not in the "ungrouped" group
for node in ['testnode', 'testnode2']:
assert node not in inventory.inventory.get_groups_dict()["ungrouped"]