freeipa/ipapython/install/common.py
Rob Crittenden 68c7b03689 Return a value if exceptions are raised in server uninstall
The AdminTool class purports to "call sys.exit() with the return
value" but most of the run implementations returned no value, or
the methods they called returned nothing so there was nothing to
return, so this was a no-op.

The fix is to capture and bubble up the return values which will
return 1 if any exceptions are caught.

This potentially affects other users in that when executing the
steps of an installer or uninstaller the highest return code
will be the exit value of that installer.

Don't use the Continuous class because it doesn't add any
value and makes catching the exceptions more difficult.

https://pagure.io/freeipa/issue/7330

Signed-off-by: Rob Crittenden rcritten@redhat.com
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
2018-03-19 17:38:41 +01:00

119 lines
2.8 KiB
Python

#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
"""
Common stuff.
"""
import logging
import traceback
from . import core
from .util import from_
__all__ = ['step', 'Installable', 'Interactive', 'Continuous', 'installer',
'uninstaller']
logger = logging.getLogger(__name__)
def step():
def decorator(func):
cls = core.Component(Step)
cls._installer = staticmethod(func)
return cls
return decorator
class Installable(core.Configurable):
"""
Configurable which does install or uninstall.
"""
uninstalling = core.Property(False)
def _get_components(self):
components = super(Installable, self)._get_components()
if self.uninstalling:
components = reversed(list(components))
return components
def _configure(self):
if self.uninstalling:
return self._uninstall()
else:
return self._install()
def _install(self):
assert not hasattr(super(Installable, self), '_install')
return super(Installable, self)._configure()
def _uninstall(self):
assert not hasattr(super(Installable, self), '_uninstall')
return super(Installable, self)._configure()
class Step(Installable):
@property
def parent(self):
raise AttributeError('parent')
def _install(self):
for unused in self._installer(self.parent):
yield from_(super(Step, self)._install())
@staticmethod
def _installer(obj):
yield
def _uninstall(self):
for unused in self._uninstaller(self.parent):
yield from_(super(Step, self)._uninstall())
@staticmethod
def _uninstaller(obj):
yield
@classmethod
def uninstaller(cls, func):
cls._uninstaller = staticmethod(func)
return cls
class Interactive(core.Configurable):
interactive = core.Property(False)
class Continuous(core.Configurable):
def _handle_execute_exception(self, exc_info):
try:
super(Continuous, self)._handle_execute_exception(exc_info)
except BaseException as e:
logger.debug("%s", traceback.format_exc())
if isinstance(e, Exception):
logger.error("%s", e)
def installer(cls):
class Installer(cls, Installable):
def __init__(self, **kwargs):
super(Installer, self).__init__(uninstalling=False,
**kwargs)
Installer.__name__ = 'installer({0})'.format(cls.__name__)
return Installer
def uninstaller(cls):
class Uninstaller(cls, Installable):
def __init__(self, **kwargs):
super(Uninstaller, self).__init__(uninstalling=True,
**kwargs)
Uninstaller.__name__ = 'uninstaller({0})'.format(cls.__name__)
return Uninstaller