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
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
-------------
.. 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.
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
"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()
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;
'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'
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"""
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,
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,
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,
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,
ingress_mode,
port,
cluster_qos_config=cluster_qos_config,
+ enable_nfsv3=enable_nfsv3,
ssl=ssl,
ssl_cert=ssl_cert,
ssl_key=ssl_key,
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
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,
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__(
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