From 924aa084dafc7b1de7c6cd62db0bf2f5ffc01667 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Mon, 11 Apr 2022 15:32:42 -0400 Subject: [PATCH] pybind/mgr: add a wrapper exception for use with Responder In order to best get a "real" exception converted to something that can be cleanly sent to the mgr response, this new exception type can be invoked directly, or with the wrap method to automatically pull as many properties as possibly from the original exception. Signed-off-by: John Mulligan (cherry picked from commit 777814d59429bc28eeee0b13201b60b672226753) --- src/pybind/mgr/object_format.py | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/pybind/mgr/object_format.py b/src/pybind/mgr/object_format.py index 2df6584b90809..7ff15c6a616b1 100644 --- a/src/pybind/mgr/object_format.py +++ b/src/pybind/mgr/object_format.py @@ -16,6 +16,8 @@ from typing import ( Optional, TYPE_CHECKING, Tuple, + Type, + TypeVar, Union, ) @@ -267,6 +269,45 @@ class UnsupportedFormat(ErrorResponseBase): return -errno.EINVAL, "", f"Unsupported format: {self.format_name}" +class ErrorResponse(ErrorResponseBase): + """General exception convertible to a mgr response.""" + + E = TypeVar("E", bound="ErrorResponse") + + def __init__(self, status: str, return_value: Optional[int] = None) -> None: + self.return_value = ( + return_value if return_value is not None else -errno.EINVAL + ) + self.status = status + + def format_response(self) -> Tuple[int, str, str]: + return (self.return_value, "", self.status) + + def mgr_return_value(self) -> int: + return self.return_value + + @property + def errno(self) -> int: + rv = self.return_value + return -rv if rv < 0 else rv + + def __repr__(self) -> str: + return f"ErrorResponse({self.status!r}, {self.return_value!r})" + + @classmethod + def wrap( + cls: Type[E], exc: Exception, return_value: Optional[int] = None + ) -> E: + if return_value is None: + try: + return_value = -int(getattr(exc, "errno")) + except (AttributeError, ValueError): + pass + err = cls(str(exc), return_value=return_value) + setattr(err, "__cause__", exc) + return err + + def _get_requested_format(f: ObjectResponseFuncType, kw: Dict[str, Any]) -> str: # todo: leave 'format' in kw dict iff its part of f's signature return kw.pop("format", None) -- 2.39.5