]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: Updated NFS default protocol to v4 and v3 is enabled only when enable_nf...
authorShweta Bhosale <Shweta.Bhosale1@ibm.com>
Wed, 21 Jan 2026 15:43:39 +0000 (21:13 +0530)
committerShweta Bhosale <Shweta.Bhosale1@ibm.com>
Thu, 30 Apr 2026 13:22:45 +0000 (18:52 +0530)
Fixes: https://tracker.ceph.com/issues/74492
Signed-off-by: Shweta Bhosale <Shweta.Bhosale1@ibm.com>
doc/cephadm/services/nfs.rst
doc/mgr/nfs.rst
src/pybind/mgr/cephadm/services/nfs.py
src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2
src/pybind/mgr/cephadm/tests/services/test_ingress.py
src/pybind/mgr/cephadm/tests/services/test_nfs.py
src/pybind/mgr/nfs/cluster.py
src/pybind/mgr/nfs/module.py
src/python-common/ceph/deployment/service_spec.py

index 07d19df950d27901a93120384973f0191970dcc0..ecb31bff93f7c667baaff22a02ff96eba334f36e 100644 (file)
@@ -60,6 +60,7 @@ Alternatively, an NFS service can be applied using a YAML specification.
         host2: 10.0.0.124
       monitoring_networks:
       - 192.168.124.0/24
+      enable_nfsv3: true
 
 
 In this example, we run the server on the non-default ``port`` of
@@ -78,6 +79,8 @@ IP address is assigned to the host, that IP address will be used. If the IP
 address is not present and ``monitoring_networks`` is specified, an IP address
 that matches one of the specified networks will be used. If neither condition
 is met, the default binding will happen on all available network interfaces.
+By default, only the NFSv4 protocol is enabled. NFSv3 can be enabled by setting
+``enable_nfsv3`` to ``true`` in the service specification.
 
 NFS over RDMA
 -------------
index e09378b26cdf34648d6042573c7b5d20534e384a..4ef7a9581b909803fa10429cd43e5c88c955ddad 100644 (file)
@@ -31,7 +31,7 @@ Create NFS Ganesha Cluster
 
 .. prompt:: bash #
 
-   ceph nfs cluster create <cluster_id> [<placement>] [--ingress] [--virtual_ip <value>] [--ingress-mode {default|keepalive-only|haproxy-standard|haproxy-protocol}] [--port <int>] [--enable-rdma] [--rdma_port <int>] [-i <spec_file>]
+   ceph nfs cluster create <cluster_id> [<placement>] [--ingress] [--virtual_ip <value>] [--ingress-mode {default|keepalive-only|haproxy-standard|haproxy-protocol}] [--port <int>] [--enable-rdma] [--rdma_port <int>] [-i <spec_file>] [--enable-nfsv3]
 
 This creates a common recovery pool for all NFS Ganesha daemons, new user based on
 ``cluster_id``, and a common NFS Ganesha config RADOS object.
@@ -62,6 +62,9 @@ cluster)::
 
 NFS can be deployed on a port other than 2049 (the default) with ``--port <port>``.
 
+By default, only NFS v4 protocol is enabled. To enable both NFS v3 and v4 protocols,
+add the ``--enable-nfsv3`` flag.
+
 To deploy NFS with a high-availability front-end (virtual IP and load balancer), add the
 ``--ingress`` flag and specify a virtual IP address. This will deploy a combination
 of keepalived and haproxy to provide an high-availability NFS frontend for the NFS
index ac01900eb0231ba3f10d9b55b362a516b305ff40..1c26f8a0644e3aa19ff8b4e63fca3294bc82a104 100644 (file)
@@ -261,7 +261,8 @@ class NFSService(CephService):
                 "tls_min_version": spec.tls_min_version,
                 "tls_ktls": spec.tls_ktls,
                 "tls_debug": spec.tls_debug,
-                "ceph_nodes": ceph_nodes
+                "ceph_nodes": ceph_nodes,
+                "protocols": "3, 4" if spec.enable_nfsv3 else "4"
             }
             if spec.enable_haproxy_protocol:
                 context["haproxy_hosts"] = self._haproxy_hosts()
index 606b1c5704f28476f16f0523faed2829a0d7b948..2d211f4e7b09ab2fbe9acec657cdc05f545ba932 100644 (file)
@@ -3,9 +3,9 @@ NFS_CORE_PARAM {
         Enable_NLM = {{ enable_nlm }};
         Enable_RQUOTA = false;
 {% if enable_rdma %}
-        Protocols = 3, 4, nfsrdma, rpcrdma;
+        Protocols = {{ protocols }}, nfsrdma, rpcrdma;
 {% else %}
-        Protocols = 3, 4;
+        Protocols = {{ protocols }};
 {% endif %}
         mount_path_pseudo = true;
         Enable_UDP = false;
index 86692935e188b30553bb5de9f9b78d269a439013..a5bbe078d6e0994e48b52353c93fd90f358b81be 100644 (file)
@@ -1188,7 +1188,7 @@ class TestIngressService:
             'NFS_CORE_PARAM {\n'
             '        Enable_NLM = true;\n'
             '        Enable_RQUOTA = false;\n'
-            '        Protocols = 3, 4;\n'
+            '        Protocols = 4;\n'
             '        mount_path_pseudo = true;\n'
             '        Enable_UDP = false;\n'
             '        NFS_Port = 2049;\n'
index 376fdea25e30cc834b600cec94fe7d796c19be73..115832e4635fd26a4a4f191b4d77edcb8b6360e8 100644 (file)
@@ -588,6 +588,32 @@ class TestNFS:
                 assert "nfsrdma" not in ganesha_conf
                 assert "NFS_RDMA_Port" not in ganesha_conf
 
+    @patch("cephadm.serve.CephadmServe._run_cephadm")
+    @patch("cephadm.services.nfs.NFSService.fence_old_ranks", MagicMock())
+    @patch("cephadm.services.nfs.NFSService.run_grace_tool", MagicMock())
+    @patch("cephadm.services.nfs.NFSService.purge", MagicMock())
+    @patch("cephadm.services.nfs.NFSService.create_rados_config_obj", MagicMock())
+    def test_nfs_enable_nfsv3(self, _run_cephadm, cephadm_module: CephadmOrchestrator):
+        _run_cephadm.side_effect = async_side_effect(('{}', '', 0))
+
+        with with_host(cephadm_module, 'test'):
+            # Test with enable_nfsv3=False (default)
+            nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']))
+            with with_service(cephadm_module, nfs_spec) as _:
+                nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
+                    CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
+                ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
+                assert "Protocols = 4;" in ganesha_conf
+
+            # Test with enable_nfsv3=True
+            nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']),
+                                      enable_nfsv3=True)
+            with with_service(cephadm_module, nfs_spec) as _:
+                nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
+                    CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
+                ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
+                assert "Protocols = 3, 4;" in ganesha_conf
+
 
 def test_nfs_colocation_ports_validation():
     """Test validation of colocation_ports in NFSServiceSpec"""
index 5a4cf057aa2252cd21df480b0a4e3cb066894f9c..1beff39ff9308f6348e08d19b2a513543c86fd3d 100644 (file)
@@ -161,6 +161,7 @@ class NFSCluster:
             ingress_mode: Optional[IngressType] = None,
             port: Optional[int] = None,
             cluster_qos_config: Optional[Dict[str, Union[str, bool, int]]] = None,
+            enable_nfsv3: bool = False,
             ssl: bool = False,
             ssl_cert: Optional[str] = None,
             ssl_key: Optional[str] = None,
@@ -206,6 +207,7 @@ class NFSCluster:
                                   virtual_ip=virtual_ip_for_ganesha,
                                   enable_haproxy_protocol=enable_haproxy_protocol,
                                   cluster_qos_config=cluster_qos_config,
+                                  enable_nfsv3=enable_nfsv3,
                                   ssl=ssl,
                                   ssl_cert=ssl_cert,
                                   ssl_key=ssl_key,
@@ -235,6 +237,7 @@ class NFSCluster:
                                   placement=PlacementSpec.from_string(placement),
                                   port=port,
                                   cluster_qos_config=cluster_qos_config,
+                                  enable_nfsv3=enable_nfsv3,
                                   ssl=ssl,
                                   ssl_cert=ssl_cert,
                                   ssl_key=ssl_key,
@@ -269,6 +272,7 @@ class NFSCluster:
             ingress_mode: Optional[IngressType] = None,
             port: Optional[int] = None,
             cluster_qos_config: Optional[Dict[str, Union[str, bool, int]]] = None,
+            enable_nfsv3: bool = False,
             ssl: bool = False,
             ssl_cert: Optional[str] = None,
             ssl_key: Optional[str] = None,
@@ -309,6 +313,7 @@ class NFSCluster:
                     ingress_mode,
                     port,
                     cluster_qos_config=cluster_qos_config,
+                    enable_nfsv3=enable_nfsv3,
                     ssl=ssl,
                     ssl_cert=ssl_cert,
                     ssl_key=ssl_key,
index ab6369e346ea15875a967bc076b220d852a1c522..7cd2aa70dccd1cf86120f439ad7af2bca8c2bedd 100644 (file)
@@ -162,6 +162,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                 port: Optional[int] = None,
                                 enable_rdma: bool = False,
                                 rdma_port: Optional[int] = None,
+                                enable_nfsv3: bool = False,
                                 inbuf: Optional[str] = None) -> None:
         """Create an NFS Cluster"""
         cluster_qos_config = None
@@ -183,6 +184,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                            virtual_ip=virtual_ip, ingress=ingress,
                                            ingress_mode=ingress_mode, port=port,
                                            cluster_qos_config=cluster_qos_config,
+                                           enable_nfsv3=enable_nfsv3,
                                            ssl=ssl,
                                            ssl_cert=ssl_cert,
                                            ssl_key=ssl_key,
index 9ac9db4587129396c691e1f971f1b2ee5abe4b5a..c0b9ff873d5ae65c42d3c5e6cc0d043914f4780b 100644 (file)
@@ -1393,6 +1393,7 @@ class NFSServiceSpec(ServiceSpec):
                  tls_min_version: Optional[str] = None,
                  tls_ciphers: Optional[str] = None,
                  colocation_ports: Optional[List[Dict[str, int]]] = None,
+                 enable_nfsv3: bool = False,
                  ):
         assert service_type == 'nfs'
         super(NFSServiceSpec, self).__init__(
@@ -1421,6 +1422,7 @@ class NFSServiceSpec(ServiceSpec):
         self.rdma_port = rdma_port
         self.cluster_qos_config = cluster_qos_config
         self.cluster_qos_port = cluster_qos_port
+        self.enable_nfsv3 = enable_nfsv3
 
         # colocation_ports is a list of port dicts for ADDITIONAL colocated daemons
         # The first daemon always uses port and monitoring_port from the spec