Commit 283ac446 authored by Jérome Perrin's avatar Jérome Perrin

cli/prune: fix a possible infinite recursion

With recursive instances, it was possible that the slapos.cfg introduce a
kind of loop and this was checking again and again the same folders.

Fix this by keeping track of the visited instance root and not visit the
same instance root twice.
parent d4690a67
Pipeline #16942 failed with stage
in 0 seconds
......@@ -92,7 +92,7 @@ def _prune(
logger, software_root, shared_root, ignored_shared_parts)
# recursively look in instance
signatures.update(getUsageSignaturesFromSubInstance(logger, instance_root))
signatures.update(getUsageSignaturesFromSubInstance(logger, instance_root, set([])))
for shared_part in glob.glob(os.path.join(shared_root, '*', '*')):
if shared_part not in ignored_shared_parts:
......@@ -140,7 +140,7 @@ def do_prune(logger, options, dry_run):
)
def getUsageSignaturesFromSubInstance(logger, instance_root):
def getUsageSignaturesFromSubInstance(logger, instance_root, visited):
"""Look at instances in instance_root to find used shared parts,
if instances are recursive slapos.
......@@ -148,6 +148,11 @@ def getUsageSignaturesFromSubInstance(logger, instance_root):
this is a recursive slapos.
"""
signatures = {}
# prevent infinite loops
if instance_root in visited:
return signatures
visited.add(instance_root)
for slapos_cfg in getInstanceSlaposCfgList(logger, instance_root):
cfg = readSlaposCfg(logger, slapos_cfg)
if not cfg:
......@@ -181,7 +186,7 @@ def getUsageSignaturesFromSubInstance(logger, instance_root):
)
else:
signatures.update(
getUsageSignaturesFromSubInstance(logger, cfg['instance_root']))
getUsageSignaturesFromSubInstance(logger, cfg['instance_root'], visited))
return signatures
......
......@@ -285,6 +285,44 @@ shared_part_list = NOT EXIST SHARED PART
software_root = {instance_software}
instance_root = anything
shared_part_list = anything
'''.format(**locals()))
do_prune(self.logger, self.config, False)
self.assertTrue(os.path.exists(used_in_software_from_instance))
def test_recursive_instance_multiple_levels(self):
used_in_software_from_instance = self._createSharedPart('used_in_software_from_instance')
instance_level1 = os.path.join(self.instance_root, 'slappart0')
instance_level1_etc = os.path.join(instance_level1, 'etc')
os.makedirs(instance_level1_etc)
instance_level1_slapos_cfg = os.path.join(instance_level1_etc, 'slapos.cfg')
with open(instance_level1_slapos_cfg, 'w') as f:
f.write('''
[slapos]
software_root = anything
instance_root = {instance_level1}
shared_part_list = anything
'''.format(**locals()))
instance_level2 = os.path.join(instance_level1, 'srv', 'runner')
instance_level2_etc = os.path.join(instance_level2, 'etc')
os.makedirs(instance_level2_etc)
instance_level2_software = os.path.join(instance_level2, 'software')
os.makedirs(instance_level2_software)
software_in_instance = self._createFakeSoftware(
'soft_in_instance_level2',
using=used_in_software_from_instance,
software_root=instance_level2_software
)
instance_level2_slapos_cfg = os.path.join(instance_level2_etc, 'slapos.cfg')
with open(instance_level2_slapos_cfg, 'w') as f:
f.write('''
[slapos]
software_root = {instance_level2_software}
instance_root = {instance_level2}
shared_part_list = anything
'''.format(**locals()))
do_prune(self.logger, self.config, False)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment