[elbe-devel] [PATCH] elbepack: soap: simplify error mapping
Thomas Weißschuh
thomas.weissschuh at linutronix.de
Tue Aug 13 15:56:25 CEST 2024
Spyne provides a dedicated hook to handle and map exceptions, "call_wrapper".
Use that to replace the custom decorator which needs to be applied to
each method and also needs custom logic for each possible method arity.
While at it, also drop the unused SoapElbeAuthenticationFailed.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh at linutronix.de>
---
debian/python3-elbe-soap.install | 1 -
elbepack/daemons/soap/esoap.py | 104 ++++++++++++-------
elbepack/daemons/soap/faults.py | 219 ---------------------------------------
3 files changed, 68 insertions(+), 256 deletions(-)
diff --git a/debian/python3-elbe-soap.install b/debian/python3-elbe-soap.install
index 97e62dd56991..1220a09a4d65 100644
--- a/debian/python3-elbe-soap.install
+++ b/debian/python3-elbe-soap.install
@@ -1,5 +1,4 @@
usr/lib/python3.*/*-packages/elbepack/daemons/soap/__init__.py
usr/lib/python3.*/*-packages/elbepack/daemons/soap/authentication.py
usr/lib/python3.*/*-packages/elbepack/daemons/soap/datatypes.py
-usr/lib/python3.*/*-packages/elbepack/daemons/soap/faults.py
usr/lib/python3.*/*-packages/elbepack/daemons/soap/esoap.py
diff --git a/elbepack/daemons/soap/esoap.py b/elbepack/daemons/soap/esoap.py
index e6e0d1766e5e..333dfe7f74b5 100644
--- a/elbepack/daemons/soap/esoap.py
+++ b/elbepack/daemons/soap/esoap.py
@@ -7,19 +7,66 @@ import binascii
import fnmatch
import os
import tarfile
+import traceback
from tempfile import NamedTemporaryFile
from spyne.decorator import rpc
from spyne.model.complex import Array
+from spyne.model.fault import Fault
from spyne.model.primitive import Boolean, Integer, String
from spyne.service import ServiceBase
-from elbepack.elbexml import ValidationMode
+from elbepack.db import ElbeDBError, InvalidLogin
+from elbepack.elbexml import ValidationError, ValidationMode
+from elbepack.projectmanager import InvalidState, ProjectManagerError
from elbepack.version import elbe_version
from .authentication import authenticated_admin, authenticated_uid
from .datatypes import SoapFile, SoapProject
-from .faults import soap_faults
+
+
+class SoapElbeDBError(Fault):
+ def __init__(self, dberr):
+ Fault.__init__(self, faultcode='ElbeDBError', faultstring=str(dberr))
+
+
+class SoapElbeProjectError(Fault):
+ def __init__(self, err):
+ Fault.__init__(
+ self,
+ faultcode='ElbeProjectError',
+ faultstring=str(err))
+
+
+class SoapElbeNotLoggedIn(Fault):
+ def __init__(self):
+ Fault.__init__(
+ self,
+ faultcode='ElbeNotLoggedIn',
+ faultstring='Not authenticated ! '
+ 'Cant let you perform this command.')
+
+
+class SoapElbeNotAuthorized(Fault):
+ def __init__(self):
+ Fault.__init__(
+ self,
+ faultcode='ElbeNotAuthorized',
+ faultstring='Not Authorized ! Cant let you perform this command.')
+
+
+class SoapElbeValidationError(Fault):
+ def __init__(self, exc):
+ Fault.__init__(
+ self,
+ faultcode='ElbeValidationError',
+ faultstring=exc.__repr__())
+
+
+class SoapElbeInvalidState(Fault):
+ def __init__(self):
+ Fault.__init__(self, faultcode='ElbeInvalidState',
+ faultstring='Project is Busy ! Operation Invalid')
class ESoap (ServiceBase):
@@ -30,13 +77,30 @@ class ESoap (ServiceBase):
self.app = None
self.transport = None
+ @classmethod
+ def call_wrapper(cls, ctx):
+ try:
+ return super().call_wrapper(ctx)
+ except InvalidState:
+ raise SoapElbeInvalidState()
+ except ProjectManagerError as e:
+ raise SoapElbeProjectError(str(e))
+ except ElbeDBError as e:
+ raise SoapElbeDBError(str(e))
+ except OSError as e:
+ raise SoapElbeProjectError('OSError: ' + str(e))
+ except ValidationError as e:
+ raise SoapElbeValidationError(e)
+ except InvalidLogin:
+ raise SoapElbeNotAuthorized()
+ except Exception:
+ raise SoapElbeProjectError(traceback.format_exc())
+
@rpc(_returns=String)
- @soap_faults
def get_version(self):
return elbe_version
@rpc(String, String, _returns=Boolean)
- @soap_faults
def login(self, user, passwd):
s = self.transport.req_env['beaker.session']
s['userid'] = self.app.pm.db.validate_login(user, passwd)
@@ -44,26 +108,22 @@ class ESoap (ServiceBase):
return True
@rpc(_returns=Array(String))
- @soap_faults
@authenticated_admin
def list_users(self):
return [u.name for u in self.app.pm.db.list_users()]
@rpc(String, String, String, String, Boolean)
- @soap_faults
@authenticated_admin
def add_user(self, name, fullname, password, email, admin):
self.app.pm.db.add_user(name, fullname, password, email, admin)
@rpc(_returns=Array(SoapProject))
- @soap_faults
@authenticated_admin
def list_projects(self):
return self.app.pm.db.list_projects()
@rpc(String, _returns=SoapProject)
- @soap_faults
@authenticated_uid
def get_project(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
@@ -71,7 +131,6 @@ class ESoap (ServiceBase):
@rpc(String, _returns=Array(SoapFile))
@authenticated_uid
- @soap_faults
def get_files(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
files = self.app.pm.db.get_project_files(builddir)
@@ -79,7 +138,6 @@ class ESoap (ServiceBase):
@rpc(String, String, String, Integer, _returns=Integer)
@authenticated_uid
- @soap_faults
def upload_file(self, uid, builddir, fname, blob, part):
fn = os.path.join(builddir, fname)
@@ -112,7 +170,6 @@ class ESoap (ServiceBase):
@rpc(String, String, Integer, _returns=String)
@authenticated_uid
- @soap_faults
def get_file(self, uid, builddir, filename, part):
self.app.pm.open_project(uid, builddir)
@@ -136,35 +193,30 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def build_chroot_tarball(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_chroot_tarball(uid)
@rpc(String)
@authenticated_uid
- @soap_faults
def build_sysroot(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_sysroot(uid)
@rpc(String)
@authenticated_uid
- @soap_faults
def build_sdk(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_sdk(uid)
@rpc(String, Boolean, Boolean)
@authenticated_uid
- @soap_faults
def build_cdroms(self, uid, builddir, build_bin, build_src):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_cdroms(uid, build_bin, build_src)
@rpc(String, Boolean, Boolean, Boolean)
@authenticated_uid
- @soap_faults
def build(self, uid, builddir, build_bin, build_src, skip_pbuilder):
self.app.pm.open_project(uid, builddir)
@@ -173,21 +225,18 @@ class ESoap (ServiceBase):
@rpc(String, Boolean, Boolean, String)
@authenticated_uid
- @soap_faults
def build_pbuilder(self, uid, builddir, cross, noccache, ccachesize):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_pbuilder(uid, cross, noccache, ccachesize)
@rpc(String)
@authenticated_uid
- @soap_faults
def update_pbuilder(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.update_pbuilder(uid)
@rpc(String)
@authenticated_uid
- @soap_faults
def start_cdrom(self, uid, builddir):
self.app.pm.open_project(
uid, builddir, url_validation=ValidationMode.NO_CHECK)
@@ -200,7 +249,6 @@ class ESoap (ServiceBase):
@rpc(String, String)
@authenticated_uid
- @soap_faults
def append_cdrom(self, uid, builddir, data):
self.app.pm.open_project(
uid, builddir, url_validation=ValidationMode.NO_CHECK)
@@ -214,7 +262,6 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def finish_cdrom(self, uid, builddir):
self.app.pm.open_project(
uid, builddir, url_validation=ValidationMode.NO_CHECK)
@@ -222,7 +269,6 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def start_pdebuild(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
@@ -234,7 +280,6 @@ class ESoap (ServiceBase):
@rpc(String, String)
@authenticated_uid
- @soap_faults
def append_pdebuild(self, uid, builddir, data):
self.app.pm.open_project(uid, builddir)
@@ -247,14 +292,12 @@ class ESoap (ServiceBase):
@rpc(String, String, Boolean)
@authenticated_uid
- @soap_faults
def finish_pdebuild(self, uid, builddir, profile, cross):
self.app.pm.open_project(uid, builddir)
self.app.pm.build_current_pdebuild(uid, profile, cross)
@rpc(String, String)
@authenticated_uid
- @soap_faults
def start_upload_orig(self, uid, builddir, fname):
self.app.pm.open_project(uid, builddir)
@@ -268,7 +311,6 @@ class ESoap (ServiceBase):
@rpc(String, String)
@authenticated_uid
- @soap_faults
def append_upload_orig(self, uid, builddir, data):
self.app.pm.open_project(uid, builddir)
@@ -281,7 +323,6 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def finish_upload_orig(self, uid, builddir):
# If we support more than one orig, we need to put the orig_files into
# some list here.
@@ -290,20 +331,17 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def reset_project(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.db.reset_project(builddir, True)
@rpc(String)
@authenticated_uid
- @soap_faults
def del_project(self, uid, builddir):
self.app.pm.del_project(uid, builddir)
@rpc(String, String, _returns=String)
@authenticated_uid
- @soap_faults
def create_project(self, uid, xml, url_validation):
with NamedTemporaryFile() as fp:
fp.write(binascii.a2b_base64(xml))
@@ -315,13 +353,11 @@ class ESoap (ServiceBase):
@rpc(_returns=String)
@authenticated_uid
- @soap_faults
def new_project(self, uid):
return self.app.pm.new_project(uid)
@rpc(String, _returns=String)
@authenticated_uid
- @soap_faults
def get_project_busy(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
ret, msg = self.app.pm.current_project_is_busy(uid)
@@ -331,14 +367,12 @@ class ESoap (ServiceBase):
@rpc(String)
@authenticated_uid
- @soap_faults
def rm_log(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
self.app.pm.rm_log(uid)
@rpc(String, _returns=String.customize(max_occurs='unbounded'))
@authenticated_uid
- @soap_faults
def list_packages(self, uid, builddir):
self.app.pm.open_project(uid, builddir)
r = []
@@ -350,7 +384,6 @@ class ESoap (ServiceBase):
@rpc(String, String)
@authenticated_uid
- @soap_faults
def tar_prjrepo(self, uid, builddir, filename):
self.app.pm.open_project(uid, builddir)
with tarfile.open(os.path.join(builddir, filename), 'w:gz') as tar:
@@ -362,7 +395,6 @@ class ESoap (ServiceBase):
@rpc(String, String)
@authenticated_uid
- @soap_faults
def include_package(self, uid, builddir, filename):
self.app.pm.open_project(uid, builddir)
self.app.pm.add_deb_package(uid, filename)
diff --git a/elbepack/daemons/soap/faults.py b/elbepack/daemons/soap/faults.py
deleted file mode 100644
index c9d870ff88ad..000000000000
--- a/elbepack/daemons/soap/faults.py
+++ /dev/null
@@ -1,219 +0,0 @@
-# ELBE - Debian Based Embedded Rootfilesystem Builder
-# SPDX-License-Identifier: GPL-3.0-or-later
-# SPDX-FileCopyrightText: 2015-2017 Linutronix GmbH
-
-from functools import wraps
-from traceback import format_exc
-
-from spyne.model.fault import Fault
-
-from elbepack.db import ElbeDBError, InvalidLogin
-from elbepack.elbexml import ValidationError
-from elbepack.projectmanager import InvalidState, ProjectManagerError
-
-
-class SoapElbeDBError(Fault):
- def __init__(self, dberr):
- Fault.__init__(self, faultcode='ElbeDBError', faultstring=str(dberr))
-
-
-class SoapElbeProjectError(Fault):
- def __init__(self, err):
- Fault.__init__(
- self,
- faultcode='ElbeProjectError',
- faultstring=str(err))
-
-
-class SoapElbeAuthenticationFailed(Fault):
- def __init__(self):
- Fault.__init__(
- self,
- faultcode='ElbeAuthenticationFailed',
- faultstring='Authentication Failed')
-
-
-class SoapElbeNotLoggedIn(Fault):
- def __init__(self):
- Fault.__init__(
- self,
- faultcode='ElbeNotLoggedIn',
- faultstring='Not authenticated ! '
- 'Cant let you perform this command.')
-
-
-class SoapElbeNotAuthorized(Fault):
- def __init__(self):
- Fault.__init__(
- self,
- faultcode='ElbeNotAuthorized',
- faultstring='Not Authorized ! Cant let you perform this command.')
-
-
-class SoapElbeValidationError(Fault):
- def __init__(self, exc):
- Fault.__init__(
- self,
- faultcode='ElbeValidationError',
- faultstring=exc.__repr__())
-
-
-class SoapElbeInvalidState(Fault):
- def __init__(self):
- Fault.__init__(self, faultcode='ElbeInvalidState',
- faultstring='Project is Busy ! Operation Invalid')
-
-
-def soap_faults(func):
- """ decorator, which wraps Exceptions to the proper
- Soap Faults, and raises these.
- """
-
- # Do not edit this code. Although using *args is tempting here,
- # it will not work because Spyne is doing introspection on the
- # function's signature. I think it would be possible to do
- # something with func.__code__.replace, but this requires deep
- # Python's internal knowledges.
-
- if func.__code__.co_argcount == 1:
- @wraps(func)
- def wrapped(self):
- try:
- return func(self)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 2:
- @wraps(func)
- def wrapped(self, arg1):
- try:
- return func(self, arg1)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 3:
- @wraps(func)
- def wrapped(self, arg1, arg2):
- try:
- return func(self, arg1, arg2)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 4:
- @wraps(func)
- def wrapped(self, arg1, arg2, arg3):
- try:
- return func(self, arg1, arg2, arg3)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 5:
- @wraps(func)
- def wrapped(self, arg1, arg2, arg3, arg4):
- try:
- return func(self, arg1, arg2, arg3, arg4)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 6:
- @wraps(func)
- def wrapped(self, arg1, arg2, arg3, arg4, arg5):
- try:
- return func(self, arg1, arg2, arg3, arg4, arg5)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
- if func.__code__.co_argcount == 7:
- @wraps(func)
- def wrapped(self, arg1, arg2, arg3, arg4, arg5, arg6):
- try:
- return func(self, arg1, arg2, arg3, arg4, arg5, arg6)
- except InvalidState:
- raise SoapElbeInvalidState()
- except ProjectManagerError as e:
- raise SoapElbeProjectError(str(e))
- except ElbeDBError as e:
- raise SoapElbeDBError(str(e))
- except OSError as e:
- raise SoapElbeProjectError('OSError: ' + str(e))
- except ValidationError as e:
- raise SoapElbeValidationError(e)
- except InvalidLogin:
- raise SoapElbeNotAuthorized()
- except Exception:
- raise SoapElbeProjectError(format_exc())
- return wrapped
-
- raise Exception(f'arg count {func.__code__.co_argcount} not implemented')
---
base-commit: fe0ef725cfcd3e6ac93b9c538a1d7a812f3fcd28
change-id: 20240813-soap-faults-52ed14bc9136
Best regards,
--
Thomas Weißschuh <thomas.weissschuh at linutronix.de>
More information about the elbe-devel
mailing list