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
...@@ -92,7 +92,7 @@ def _prune( ...@@ -92,7 +92,7 @@ def _prune(
logger, software_root, shared_root, ignored_shared_parts) logger, software_root, shared_root, ignored_shared_parts)
# recursively look in instance # 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, '*', '*')): for shared_part in glob.glob(os.path.join(shared_root, '*', '*')):
if shared_part not in ignored_shared_parts: if shared_part not in ignored_shared_parts:
...@@ -140,7 +140,7 @@ def do_prune(logger, options, dry_run): ...@@ -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, """Look at instances in instance_root to find used shared parts,
if instances are recursive slapos. if instances are recursive slapos.
...@@ -148,6 +148,11 @@ def getUsageSignaturesFromSubInstance(logger, instance_root): ...@@ -148,6 +148,11 @@ def getUsageSignaturesFromSubInstance(logger, instance_root):
this is a recursive slapos. this is a recursive slapos.
""" """
signatures = {} signatures = {}
# prevent infinite loops
if instance_root in visited:
return signatures
visited.add(instance_root)
for slapos_cfg in getInstanceSlaposCfgList(logger, instance_root): for slapos_cfg in getInstanceSlaposCfgList(logger, instance_root):
cfg = readSlaposCfg(logger, slapos_cfg) cfg = readSlaposCfg(logger, slapos_cfg)
if not cfg: if not cfg:
...@@ -181,7 +186,7 @@ def getUsageSignaturesFromSubInstance(logger, instance_root): ...@@ -181,7 +186,7 @@ def getUsageSignaturesFromSubInstance(logger, instance_root):
) )
else: else:
signatures.update( signatures.update(
getUsageSignaturesFromSubInstance(logger, cfg['instance_root'])) getUsageSignaturesFromSubInstance(logger, cfg['instance_root'], visited))
return signatures return signatures
......
...@@ -285,6 +285,44 @@ shared_part_list = NOT EXIST SHARED PART ...@@ -285,6 +285,44 @@ shared_part_list = NOT EXIST SHARED PART
software_root = {instance_software} software_root = {instance_software}
instance_root = anything instance_root = anything
shared_part_list = 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())) '''.format(**locals()))
do_prune(self.logger, self.config, False) 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