From 001127f8bdbe7efea8bfb7bba6595ed28360c319 Mon Sep 17 00:00:00 2001 From: Chris Church Date: Thu, 6 Aug 2015 14:59:04 -0400 Subject: [PATCH] Limit max depth when building mapping of group depths to avoid hitting recursion limit. Fixes https://trello.com/c/2zc0odvX --- awx/main/models/inventory.py | 3 +++ .../tests/commands/commands_monolithic.py | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 10649d9c1b..3b556d04f4 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -222,6 +222,9 @@ class Inventory(CommonModel): def update_group_depths(group_pk, current_depth=0): max_depth = group_depths.get(group_pk, -1) + # Arbitrarily limit depth to avoid hitting Python recursion limit (which defaults to 1000). + if current_depth > 100: + return if current_depth > max_depth: group_depths[group_pk] = current_depth for child_pk in group_children_map.get(group_pk, set()): diff --git a/awx/main/tests/commands/commands_monolithic.py b/awx/main/tests/commands/commands_monolithic.py index 233af5dcad..3335c2825f 100644 --- a/awx/main/tests/commands/commands_monolithic.py +++ b/awx/main/tests/commands/commands_monolithic.py @@ -99,6 +99,19 @@ lb[01:09:2].example.us even_odd=odd media[0:9][0:9].example.cc ''' +TEST_INVENTORY_INI_WITH_RECURSIVE_GROUPS = '''\ +[family:children] +parent + +[parent:children] +child + +[child:children] +grandchild + +[grandchild:children] +parent +''' class BaseCommandMixin(object): ''' @@ -974,6 +987,16 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): source=self.ini_path) self.assertTrue(isinstance(result, ValueError), result) + def test_ini_file_with_recursive_groups(self): + self.create_test_ini(ini_content=TEST_INVENTORY_INI_WITH_RECURSIVE_GROUPS) + new_inv = self.organizations[0].inventories.create(name='new') + self.assertEqual(new_inv.hosts.count(), 0) + self.assertEqual(new_inv.groups.count(), 0) + result, stdout, stderr = self.run_command('inventory_import', + inventory_id=new_inv.pk, + source=self.ini_path) + self.assertEqual(result, None, stdout + stderr) + def test_executable_file(self): # Use existing inventory as source. old_inv = self.inventories[1]