From: Shweta Bhosale Date: Fri, 6 Feb 2026 12:57:58 +0000 (+0530) Subject: mgr/nfs: set nfs export protocols based on cluster's protocol settings X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=44c13620288c434aef6fc00aa4e7a8c64c7e4134;p=ceph.git mgr/nfs: set nfs export protocols based on cluster's protocol settings Fixes: https://tracker.ceph.com/issues/74492 Signed-off-by: Shweta Bhosale --- diff --git a/src/pybind/mgr/nfs/export.py b/src/pybind/mgr/nfs/export.py index 9194f380eb8..304d7c3511e 100644 --- a/src/pybind/mgr/nfs/export.py +++ b/src/pybind/mgr/nfs/export.py @@ -162,6 +162,25 @@ class ExportMgr: self._exports: Optional[Dict[str, List[Export]]] = export_ls self.skip_notify_nfs_server = False + def _get_cluster_protocols(self, cluster_id: str) -> List[int]: + """Get the list of supported NFS protocols for a cluster. + """ + try: + import orchestrator + from ceph.deployment.service_spec import NFSServiceSpec + + completion = self.mgr.describe_service(service_type='nfs', service_name=f'nfs.{cluster_id}') + services = orchestrator.raise_if_exception(completion) + for service in services: + if service.spec and isinstance(service.spec, NFSServiceSpec): + spec = cast(NFSServiceSpec, service.spec) + if getattr(spec, 'enable_nfsv3', False): + return [3, 4] + return [4] + except Exception as e: + log.debug(f"Failed to get cluster protocols for {cluster_id}: {e}, defaulting to v4 only") + return [4] + @property def exports(self) -> Dict[str, List[Export]]: if self._exports is None: @@ -696,6 +715,8 @@ class ExportMgr: _validate_cmount_path(cmount_path, path) # type: ignore pseudo_path = normalize_path(pseudo_path) + # Get the protocols based on cluster's enable_nfsv3 setting + protocols = self._get_cluster_protocols(cluster_id) export_dict = { "pseudo": pseudo_path, @@ -710,6 +731,7 @@ class ExportMgr: "clients": clients, "sectype": sectype, "XprtSec": xprtsec, + "protocols": protocols, } if transports is not None: export_dict["transports"] = transports @@ -750,6 +772,9 @@ class ExportMgr: if not bucket and not user_id: raise ErrorResponse("Must specify either bucket or user_id") + # Get the protocols based on cluster's enable_nfsv3 setting + protocols = self._get_cluster_protocols(cluster_id) + export_dict = { "pseudo": pseudo_path, "path": bucket or '/', @@ -762,6 +787,7 @@ class ExportMgr: "clients": clients, "sectype": sectype, "XprtSec": xprtsec, + "protocols": protocols, } if transports is not None: export_dict["transports"] = transports @@ -825,6 +851,10 @@ class ExportMgr: else: new_export_dict['fsal']['cmount_path'] = '/' + # Set protocols based on cluster's enable_nfsv3 setting if not explicitly specified + if 'protocols' not in new_export_dict: + new_export_dict['protocols'] = self._get_cluster_protocols(cluster_id) + new_export = self.create_export_from_dict( cluster_id, new_export_dict.get('export_id', self._gen_export_id(cluster_id)), diff --git a/src/pybind/mgr/nfs/ganesha_conf.py b/src/pybind/mgr/nfs/ganesha_conf.py index 04f97bcba55..9a5b38fb92a 100644 --- a/src/pybind/mgr/nfs/ganesha_conf.py +++ b/src/pybind/mgr/nfs/ganesha_conf.py @@ -474,7 +474,7 @@ class Export: ex_dict.get('access_type', 'RO'), ex_dict.get('squash', 'no_root_squash'), ex_dict.get('security_label', True), - ex_dict.get('protocols', [3, 4]), + ex_dict.get('protocols', [4]), ex_dict.get('transports', ['TCP']), FSAL.from_dict(ex_dict.get('fsal', {})), [Client.from_dict(client) for client in ex_dict.get('clients', [])], diff --git a/src/pybind/mgr/nfs/tests/test_nfs.py b/src/pybind/mgr/nfs/tests/test_nfs.py index 57db70a2002..3959f44f28a 100644 --- a/src/pybind/mgr/nfs/tests/test_nfs.py +++ b/src/pybind/mgr/nfs/tests/test_nfs.py @@ -126,7 +126,7 @@ EXPORT { Path = /; Pseudo = /cephfs_b/; Access_Type = RW; - Protocols = 4; + Protocols = 3, 4; Attr_Expiration_Time = 0; FSAL { @@ -491,7 +491,7 @@ NFS_CORE_PARAM { assert export.pseudo == "/cephfs_b/" assert export.access_type == "RW" assert export.squash == "no_root_squash" - assert export.protocols == [4] + assert export.protocols == [3, 4] assert export.fsal.name == "CEPH" assert export.fsal.user_id == "nfs.foo.b.lgudhr" assert export.fsal.fs_name == "b" @@ -1122,7 +1122,7 @@ NFS_CORE_PARAM { assert export.pseudo == "/mybucket" assert export.access_type == "none" assert export.squash == "none" - assert export.protocols == [3, 4] + assert export.protocols == [4] assert export.transports == ["TCP"] assert export.fsal.name == "RGW" assert export.fsal.user_id == "bucket_owner_user" @@ -1166,7 +1166,7 @@ NFS_CORE_PARAM { assert export.pseudo == "/mybucket" assert export.access_type == "none" assert export.squash == "none" - assert export.protocols == [3, 4] + assert export.protocols == [4] assert export.transports == ["TCP"] assert export.fsal.name == "RGW" assert export.fsal.access_key_id == "the_access_key" @@ -1208,7 +1208,7 @@ NFS_CORE_PARAM { assert export.pseudo == "/mybucket" assert export.access_type == "none" assert export.squash == "none" - assert export.protocols == [3, 4] + assert export.protocols == [4] assert export.transports == ["TCP"] assert export.fsal.name == "RGW" assert export.fsal.access_key_id == "the_access_key" @@ -1257,7 +1257,7 @@ NFS_CORE_PARAM { assert export.pseudo == "/cephfs2" assert export.access_type == "none" assert export.squash == "none" - assert export.protocols == [3, 4] + assert export.protocols == [4] assert export.transports == ["TCP"] assert export.fsal.name == "CEPH" assert export.fsal.user_id == "nfs.foo.myfs.86ca58ef" @@ -1389,7 +1389,7 @@ EXPORT { assert export.pseudo == "/cephfs3" assert export.access_type == "RW" assert export.squash == "root" - assert export.protocols == [3, 4] + assert export.protocols == [4] assert export.fsal.name == "CEPH" assert export.fsal.user_id == "nfs.foo.myfs.86ca58ef" assert export.fsal.cephx_key == "thekeyforclientabc"