Commit 7b2da457 authored by Jérome Perrin's avatar Jérome Perrin

prune: tolerate all forms of broken slapos.cfg in instance

When we recurse in instance to find nested slapos that might be using
parts from ourselves, we check all files named slapos.cfg but we may
encounter some slapos.cfg that are not actual slapos config files, for
example in testnodes we have a working copy of slapos repository which
contains a stack/slapos.cfg which is completly different.

This was breaking prune with an error like this:

    2020-04-29 20:07:28 slapos[2097] DEBUG Reading config at /srv/slapgrid/slappart9/srv/testnode/czp/slapos-repository/stack/slapos.cfg
    2020-04-29 20:07:28 slapos[2097] ERROR No section: 'slapos'
parent 0cf9c384
Pipeline #9195 canceled with stage
in 0 seconds
...@@ -138,14 +138,38 @@ def getUsageSignaturesFromSubInstance(logger, instance_root): ...@@ -138,14 +138,38 @@ def getUsageSignaturesFromSubInstance(logger, instance_root):
signatures = {} signatures = {}
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:
return {}
shared_root = None shared_root = None
if cfg['shared_part_list']: if cfg['shared_part_list']:
shared_root = cfg['shared_part_list'][-1] shared_root = cfg['shared_part_list'][-1]
signatures.update( if not os.path.exists(shared_root):
getUsageSignatureFromSoftwareAndSharedPart( logger.debug(
logger, cfg['software_root'], shared_root)) "Ignoring non existant shared root %s from %s",
signatures.update( shared_root,
getUsageSignaturesFromSubInstance(logger, cfg['instance_root'])) slapos_cfg,
)
shared_root = None
if not os.path.exists(cfg['software_root']):
logger.debug(
"Ignoring non existant software root %s from %s",
cfg['software_root'],
slapos_cfg,
)
else:
signatures.update(
getUsageSignatureFromSoftwareAndSharedPart(
logger, cfg['software_root'], shared_root))
if not os.path.exists(cfg['instance_root']):
logger.debug(
"Ignoring non existant instance root %s from %s",
cfg['instance_root'],
slapos_cfg,
)
else:
signatures.update(
getUsageSignaturesFromSubInstance(logger, cfg['instance_root']))
return signatures return signatures
...@@ -163,12 +187,16 @@ def readSlaposCfg(logger, path): ...@@ -163,12 +187,16 @@ def readSlaposCfg(logger, path):
""" """
logger.debug('Reading config at %s', path) logger.debug('Reading config at %s', path)
parser = configparser.ConfigParser({'shared_part_list': ''}) parser = configparser.ConfigParser({'shared_part_list': ''})
parser.read([path]) try:
cfg = { parser.read([path])
cfg = {
'software_root': parser.get('slapos', 'software_root'), 'software_root': parser.get('slapos', 'software_root'),
'instance_root': parser.get('slapos', 'instance_root'), 'instance_root': parser.get('slapos', 'instance_root'),
'shared_part_list': parser.get('slapos', 'shared_part_list').splitlines() 'shared_part_list': parser.get('slapos', 'shared_part_list').splitlines()
} }
except configparser.Error:
logger.debug('Ignored config at %s because of error', path, exc_info=True)
return None
logger.debug('Read config: %s', cfg) logger.debug('Read config: %s', cfg)
return cfg return cfg
......
...@@ -197,3 +197,52 @@ shared_part_list = ...@@ -197,3 +197,52 @@ shared_part_list =
self.logger.warning.assert_called_with( self.logger.warning.assert_called_with(
'Unusued shared parts at %s%s', not_used, ' ... removed') 'Unusued shared parts at %s%s', not_used, ' ... removed')
def test_recursive_instance_broken_slapos_cfg(self):
instance = os.path.join(self.instance_root, 'slappart0')
instance_etc = os.path.join(instance, 'etc')
os.makedirs(instance_etc)
instance_slapos_cfg = os.path.join(instance_etc, 'slapos.cfg')
# slapos.cfg might be not valid .ini file
with open(instance_slapos_cfg, 'w') as f:
f.write('this is not an actual slapos.cfg')
do_prune(self.logger, self.config, False)
self.logger.debug.assert_any_call(
'Ignored config at %s because of error', instance_slapos_cfg, exc_info=True)
# ... or an ini file without [slapos] section
with open(instance_slapos_cfg, 'w') as f:
f.write('[something]')
do_prune(self.logger, self.config, False)
self.logger.debug.assert_any_call(
'Ignored config at %s because of error', instance_slapos_cfg, exc_info=True)
# ... or referencing non existant paths
with open(instance_slapos_cfg, 'w') as f:
f.write('''
[slapos]
software_root = NOT EXIST SOFTWARE
instance_root = NOT EXIST INSTSTANCE
shared_part_list = NOT EXIST SHARED PART
''')
do_prune(self.logger, self.config, False)
self.assertIn(
mock.call(
'Ignoring non existant software root %s from %s',
'NOT EXIST SOFTWARE',
instance_slapos_cfg),
self.logger.debug.mock_calls)
self.assertIn(
mock.call(
'Ignoring non existant instance root %s from %s',
'NOT EXIST INSTSTANCE',
instance_slapos_cfg),
self.logger.debug.mock_calls)
self.assertIn(
mock.call(
'Ignoring non existant shared root %s from %s',
'NOT EXIST SHARED PART',
instance_slapos_cfg),
self.logger.debug.mock_calls)
\ No newline at end of file
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