From: John Mulligan Date: Thu, 5 May 2022 18:31:48 +0000 (-0400) Subject: mgr/nfs: convert _cmd_nfs_export_create_cephfs to use Responder decorator X-Git-Tag: v18.1.0~491^2~11 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ff5730a8e863c723b69e1f53e117ce28881867b7;p=ceph.git mgr/nfs: convert _cmd_nfs_export_create_cephfs to use Responder decorator Signed-off-by: John Mulligan --- diff --git a/src/pybind/mgr/nfs/export.py b/src/pybind/mgr/nfs/export.py index f336d718491d..4646696ec151 100644 --- a/src/pybind/mgr/nfs/export.py +++ b/src/pybind/mgr/nfs/export.py @@ -31,6 +31,7 @@ from .exception import NFSException, NFSInvalidOperation, FSNotFound from .utils import ( CONF_PREFIX, EXPORT_PREFIX, + NonFatalError, USER_CONF_PREFIX, export_obj_name, conf_obj_name, @@ -378,8 +379,8 @@ class ExportMgr: raise ErrorResponse(f"Cluster {cluster_id!r} does not exist", return_value=-errno.ENOENT) - @export_cluster_checker - def create_export(self, addr: Optional[List[str]] = None, **kwargs: Any) -> Tuple[int, str, str]: + def create_export(self, addr: Optional[List[str]] = None, **kwargs: Any) -> Dict[str, Any]: + self._validate_cluster_id(kwargs['cluster_id']) # if addr(s) are provided, construct client list and adjust outer block clients = [] if addr: @@ -409,7 +410,8 @@ class ExportMgr: return self.create_rgw_export(**kwargs) raise NotImplementedError() except Exception as e: - return exception_handler(e, f"Failed to create {kwargs['pseudo_path']} export for {kwargs['cluster_id']}") + log.exception(f"Failed to create {kwargs['pseudo_path']} export for {kwargs['cluster_id']}") + raise ErrorResponse.wrap(e) @export_cluster_checker def delete_export(self, @@ -646,7 +648,7 @@ class ExportMgr: squash: str, access_type: str, clients: list = [], - sectype: Optional[List[str]] = None) -> Tuple[int, str, str]: + sectype: Optional[List[str]] = None) -> Dict[str, Any]: pseudo_path = normalize_path(pseudo_path) if not self._fetch_export(cluster_id, pseudo_path): @@ -676,8 +678,8 @@ class ExportMgr: "cluster": cluster_id, "mode": export.access_type, } - return (0, json.dumps(result, indent=4), '') - return 0, "", "Export already exists" + return result + raise NonFatalError("Export already exists") def create_rgw_export(self, cluster_id: str, @@ -688,11 +690,11 @@ class ExportMgr: bucket: Optional[str] = None, user_id: Optional[str] = None, clients: list = [], - sectype: Optional[List[str]] = None) -> Tuple[int, str, str]: + sectype: Optional[List[str]] = None) -> Dict[str, Any]: pseudo_path = normalize_path(pseudo_path) if not bucket and not user_id: - return -errno.EINVAL, "", "Must specify either bucket or user_id" + raise ErrorResponse("Must specify either bucket or user_id") if not self._fetch_export(cluster_id, pseudo_path): export = self.create_export_from_dict( @@ -721,8 +723,8 @@ class ExportMgr: "mode": export.access_type, "squash": export.squash, } - return (0, json.dumps(result, indent=4), '') - return 0, "", "Export already exists" + return result + raise NonFatalError("Export already exists") def _apply_export( self, diff --git a/src/pybind/mgr/nfs/module.py b/src/pybind/mgr/nfs/module.py index 537c6be39eb0..0e28e1b79346 100644 --- a/src/pybind/mgr/nfs/module.py +++ b/src/pybind/mgr/nfs/module.py @@ -26,6 +26,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): self.inited = True @CLICommand('nfs export create cephfs', perm='rw') + @object_format.Responder() def _cmd_nfs_export_create_cephfs( self, cluster_id: str, @@ -36,7 +37,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): client_addr: Optional[List[str]] = None, squash: str = 'none', sectype: Optional[List[str]] = None, - ) -> Tuple[int, str, str]: + ) -> Dict[str, Any]: """Create a CephFS export""" return self.export_mgr.create_export( fsal_type='cephfs', @@ -51,6 +52,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): ) @CLICommand('nfs export create rgw', perm='rw') + @object_format.Responder() def _cmd_nfs_export_create_rgw( self, cluster_id: str, @@ -61,7 +63,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): client_addr: Optional[List[str]] = None, squash: str = 'none', sectype: Optional[List[str]] = None, - ) -> Tuple[int, str, str]: + ) -> Dict[str, Any]: """Create an RGW export""" return self.export_mgr.create_export( fsal_type='rgw', diff --git a/src/pybind/mgr/nfs/tests/test_nfs.py b/src/pybind/mgr/nfs/tests/test_nfs.py index 5607396bbe00..97512f1a356d 100644 --- a/src/pybind/mgr/nfs/tests/test_nfs.py +++ b/src/pybind/mgr/nfs/tests/test_nfs.py @@ -924,7 +924,7 @@ NFS_CORE_PARAM { squash='root', addr=["192.168.0.0/16"] ) - assert r[0] == 0 + assert r["bind"] == "/mybucket" ls = conf.list_exports(cluster_id=self.cluster_id) assert len(ls) == 3 @@ -967,7 +967,7 @@ NFS_CORE_PARAM { squash='root', addr=["192.168.0.0/16"] ) - assert r[0] == 0 + assert r["bind"] == "/mybucket" ls = conf.list_exports(cluster_id=self.cluster_id) assert len(ls) == 3 @@ -1009,7 +1009,7 @@ NFS_CORE_PARAM { squash='root', addr=["192.168.0.0/16"] ) - assert r[0] == 0 + assert r["bind"] == "/mybucket" ls = conf.list_exports(cluster_id=self.cluster_id) assert len(ls) == 3 @@ -1052,7 +1052,7 @@ NFS_CORE_PARAM { squash='root', addr=["192.168.1.0/8"], ) - assert r[0] == 0 + assert r["bind"] == "/cephfs2" ls = conf.list_exports(cluster_id=self.cluster_id) assert len(ls) == 3 diff --git a/src/pybind/mgr/nfs/utils.py b/src/pybind/mgr/nfs/utils.py index ac857d6d920e..485c5b180f85 100644 --- a/src/pybind/mgr/nfs/utils.py +++ b/src/pybind/mgr/nfs/utils.py @@ -1,5 +1,6 @@ -from typing import List, TYPE_CHECKING +from typing import List, Tuple, TYPE_CHECKING +from object_format import ErrorResponseBase import orchestrator if TYPE_CHECKING: @@ -10,6 +11,21 @@ CONF_PREFIX: str = "conf-nfs." USER_CONF_PREFIX: str = "userconf-nfs." +class NonFatalError(ErrorResponseBase): + """Raise this exception when you want to interrupt the flow of a function + and return an informative message to the user. In certain situations the + NFS MGR module wants to indicate an action was or was not taken but still + return a success code so that non-interactive scripts continue as if the + overall action was completed. + """ + def __init__(self, msg: str) -> None: + super().__init__(msg) + self.msg = msg + + def format_response(self) -> Tuple[int, str, str]: + return 0, "", self.msg + + def export_obj_name(export_id: int) -> str: """Return a rados object name for the export.""" return f"{EXPORT_PREFIX}{export_id}"