From a1643870dbcdd2e1a297bb8c77c8fc18d51183a8 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Mon, 21 Jul 2025 15:09:38 +0200 Subject: [PATCH] Optimized auto playbook creation --- cli/build/inventory/full.py | 22 ++++++-- tests/unit/cli/build/inventory/__init__.py | 0 tests/unit/cli/build/inventory/test_full.py | 57 +++++++++++++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 tests/unit/cli/build/inventory/__init__.py create mode 100644 tests/unit/cli/build/inventory/test_full.py diff --git a/cli/build/inventory/full.py b/cli/build/inventory/full.py index db833f96..fb852367 100644 --- a/cli/build/inventory/full.py +++ b/cli/build/inventory/full.py @@ -16,7 +16,7 @@ import json def build_group_inventory(apps, host): """ - Builds a group-based Ansible inventory: each app is a group containing the host. + Build an Ansible inventory in which each application is a group containing the given host. """ groups = {app: {"hosts": [host]} for app in apps} inventory = { @@ -30,7 +30,7 @@ def build_group_inventory(apps, host): def build_hostvar_inventory(apps, host): """ - Alternative: Builds an inventory where all invokables are set as hostvars (as a list). + Alternative: Build an inventory where all invokable apps are set as a host variable (as a list). """ return { "all": { @@ -80,6 +80,12 @@ def main(): '-o', '--output', help='Write output to file instead of stdout' ) + parser.add_argument( + '-i', '--ignore', + action='append', + default=[], + help='Application ID(s) to ignore (can be specified multiple times or comma-separated)' + ) args = parser.parse_args() try: @@ -91,13 +97,21 @@ def main(): sys.stderr.write(f"Error: {e}\n") sys.exit(1) - # Select inventory style + # Combine all ignore arguments into a flat set + ignore_ids = set() + for entry in args.ignore: + ignore_ids.update(i.strip() for i in entry.split(',') if i.strip()) + + if ignore_ids: + apps = [app for app in apps if app not in ignore_ids] + + # Build the requested inventory style if args.inventory_style == 'group': inventory = build_group_inventory(apps, args.host) else: inventory = build_hostvar_inventory(apps, args.host) - # Output in chosen format + # Output in the chosen format if args.format == 'json': output = json.dumps(inventory, indent=2) else: diff --git a/tests/unit/cli/build/inventory/__init__.py b/tests/unit/cli/build/inventory/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/cli/build/inventory/test_full.py b/tests/unit/cli/build/inventory/test_full.py new file mode 100644 index 00000000..e5afc679 --- /dev/null +++ b/tests/unit/cli/build/inventory/test_full.py @@ -0,0 +1,57 @@ +import unittest +import sys +import os +import importlib.util +PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../../')) +SCRIPT_PATH = os.path.join(PROJECT_ROOT, 'cli', 'build', 'inventory', 'full.py') +spec = importlib.util.spec_from_file_location('full', SCRIPT_PATH) +full = importlib.util.module_from_spec(spec) +spec.loader.exec_module(full) + +class TestFullInventoryScript(unittest.TestCase): + + def test_build_group_inventory(self): + apps = ['app1', 'app2'] + host = 'myhost' + inventory = full.build_group_inventory(apps, host) + self.assertIn('all', inventory) + self.assertIn('app1', inventory) + self.assertIn('app2', inventory) + self.assertEqual(inventory['app1'], {'hosts': [host]}) + self.assertEqual(inventory['all']['hosts'], [host]) + self.assertIn('app1', inventory['all']['children']) + + def test_build_hostvar_inventory(self): + apps = ['foo', 'bar'] + host = 'testhost' + inventory = full.build_hostvar_inventory(apps, host) + self.assertIn('all', inventory) + self.assertIn('_meta', inventory) + self.assertIn('hostvars', inventory['_meta']) + self.assertEqual(inventory['_meta']['hostvars'][host]['invokable_applications'], apps) + self.assertEqual(inventory['all']['hosts'], [host]) + + def test_ignore_filtering(self): + # Simulate argument parsing logic for ignore flattening + ignore_args = ['foo,bar', 'baz'] + ignore_ids = set() + for entry in ignore_args: + ignore_ids.update(i.strip() for i in entry.split(',') if i.strip()) + self.assertEqual(ignore_ids, {'foo', 'bar', 'baz'}) + + # Filtering list + apps = ['foo', 'bar', 'baz', 'other'] + filtered = [app for app in apps if app not in ignore_ids] + self.assertEqual(filtered, ['other']) + + def test_ignore_filtering_empty(self): + ignore_args = [] + ignore_ids = set() + for entry in ignore_args: + ignore_ids.update(i.strip() for i in entry.split(',') if i.strip()) + apps = ['a', 'b'] + filtered = [app for app in apps if app not in ignore_ids] + self.assertEqual(filtered, ['a', 'b']) + +if __name__ == '__main__': + unittest.main()