From 3eb34c3ce7feaf51012c3338a03882b0d103138a Mon Sep 17 00:00:00 2001 From: silvacarloss Date: Fri, 24 Mar 2023 15:02:21 -0300 Subject: [PATCH] Add preferred info to ceph nfs export locations Change the Ceph NFS helpers to update the export locations preferred field based on the configuration. The preferred export location will always relate to the Ceph ADM deployed Ganesha cluster. Partial-Bug: #2035137 Change-Id: I9b05a6444b8ac98f79f297fec9c74a45ef11429d --- manila/share/drivers/cephfs/driver.py | 51 +++++++++--- .../tests/share/drivers/cephfs/test_driver.py | 78 ++++++++++++++++++- ...rred-export-location-d1f228a51df8c8b4.yaml | 24 ++++++ 3 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 releasenotes/notes/bug-2035137-ceph-nfs-set-preferred-export-location-d1f228a51df8c8b4.yaml diff --git a/manila/share/drivers/cephfs/driver.py b/manila/share/drivers/cephfs/driver.py index 0e24407e2e..8403f5b517 100644 --- a/manila/share/drivers/cephfs/driver.py +++ b/manila/share/drivers/cephfs/driver.py @@ -996,19 +996,22 @@ class NFSProtocolHelperMixin(): # `cephfs_ganesha_server_ip` wasn't possibly set and the used # address is the hostname try: - server_address = driver_helpers.escaped_address(export_ip) + server_address = driver_helpers.escaped_address( + export_ip['ip']) except ValueError: - server_address = export_ip + server_address = export_ip['ip'] export_path = "{server_address}:{mount_path}".format( server_address=server_address, mount_path=subvolume_path) LOG.info("Calculated export path for share %(id)s: %(epath)s", {"id": share['id'], "epath": export_path}) + export_location = { 'path': export_path, 'is_admin_only': False, 'metadata': {}, + 'preferred': export_ip['preferred'] } export_locations.append(export_location) return export_locations @@ -1039,7 +1042,7 @@ class NFSProtocolHelperMixin(): for export_ip in self.export_ips: self.configured_ip_versions.add( - ipaddress.ip_address(str(export_ip)).version) + ipaddress.ip_address(str(export_ip['ip'])).version) except Exception: # export_ips contained a hostname, safest thing is to # claim support for IPv4 and IPv6 address families @@ -1145,9 +1148,13 @@ class NFSProtocolHelper(NFSProtocolHelperMixin, ganesha.GaneshaNASHelper2): rados_command(self.rados_client, "fs subvolume deauthorize", argdict) def _get_export_ips(self): - export_ips = self.config.cephfs_ganesha_export_ips - if not export_ips: - export_ips = [self.ganesha_host] + ganesha_export_ips = self.config.cephfs_ganesha_export_ips + if not ganesha_export_ips: + ganesha_export_ips = [self.ganesha_host] + + export_ips = [] + for ip in ganesha_export_ips: + export_ips.append({'ip': ip, 'preferred': False}) return export_ips @@ -1186,11 +1193,22 @@ class NFSClusterProtocolHelper(NFSProtocolHelperMixin, ganesha.NASHelperBase): return self._nfs_clusterid + def _get_configured_export_ips(self): + ganesha_server_ips = ( + self.configuration.safe_get('cephfs_ganesha_export_ips') or []) + if not ganesha_server_ips: + ganesha_server_ips = ( + self.configuration.safe_get('cephfs_ganesha_server_ip')) + ganesha_server_ips = ( + [ganesha_server_ips] if ganesha_server_ips else []) + + return ganesha_server_ips + def _get_export_ips(self): """Get NFS cluster export ips.""" nfs_clusterid = self.nfs_clusterid - export_ips = [] - + ceph_nfs_export_ips = [] + ganesha_export_ips = self._get_configured_export_ips() argdict = { "cluster_id": nfs_clusterid, } @@ -1207,17 +1225,28 @@ class NFSClusterProtocolHelper(NFSProtocolHelperMixin, ganesha.NASHelperBase): if not vip: hosts = nfs_cluster_info[nfs_clusterid]["backend"] for host in hosts: - export_ips.append(host["ip"]) + ceph_nfs_export_ips.append(host["ip"]) else: - export_ips.append(vip) + ceph_nfs_export_ips.append(vip) # there are no export IPs, there are no NFS servers we can use - if not export_ips: + if not ceph_nfs_export_ips: msg = _("There are no NFS servers available to use. " "Please check the health of your Ceph cluster " "and restart the manila share service.") raise exception.ShareBackendException(msg=msg) + export_ips = [] + for ip in ceph_nfs_export_ips: + export_ips.append({'ip': ip, 'preferred': True}) + + # It's possible for deployers to state additional + # NFS interfaces directly via manila.conf. If they do, + # these are represented as non-preferred export paths. + # This is mostly to allow NFS-Ganesha server migrations. + for ip in ganesha_export_ips: + export_ips.append({'ip': ip, 'preferred': False}) + return export_ips def check_for_setup_error(self): diff --git a/manila/tests/share/drivers/cephfs/test_driver.py b/manila/tests/share/drivers/cephfs/test_driver.py index d9ba75218d..ae0b0fc8cb 100644 --- a/manila/tests/share/drivers/cephfs/test_driver.py +++ b/manila/tests/share/drivers/cephfs/test_driver.py @@ -1070,7 +1070,8 @@ class NFSProtocolHelperTestCase(test.TestCase): [{ 'path': '1.2.3.4:/foo/bar', 'is_admin_only': False, - 'metadata': {} + 'metadata': {}, + 'preferred': False }], ret) def test_get_export_locations_with_export_ips_configured(self): @@ -1099,16 +1100,19 @@ class NFSProtocolHelperTestCase(test.TestCase): 'path': '127.0.0.1:/foo/bar', 'is_admin_only': False, 'metadata': {}, + 'preferred': False }, { 'path': '[fd3f:c057:1192:1::1]:/foo/bar', 'is_admin_only': False, 'metadata': {}, + 'preferred': False }, { 'path': '[::1]:/foo/bar', 'is_admin_only': False, 'metadata': {}, + 'preferred': False }, ], ret) @@ -1394,10 +1398,12 @@ class NFSClusterProtocolHelperTestCase(test.TestCase): 'path': '10.0.0.10:/foo/bar', 'is_admin_only': False, 'metadata': {}, + 'preferred': True }, { 'path': '10.0.0.11:/foo/bar', 'is_admin_only': False, 'metadata': {}, + 'preferred': True }] export_locations = ( @@ -1410,6 +1416,76 @@ class NFSClusterProtocolHelperTestCase(test.TestCase): self.assertEqual(expected_export_locations, export_locations) + @ddt.data( + ('cephfs_ganesha_server_ip', '10.0.0.1'), + ('cephfs_ganesha_export_ips', ['10.0.0.2, 10.0.0.3']) + ) + @ddt.unpack + def test_get_export_locations_ganesha_still_configured(self, opt, val): + cluster_info_prefix = "nfs cluster info" + nfs_clusterid = self._nfscluster_protocol_helper.nfs_clusterid + self.fake_conf.set_default(opt, val) + + cluster_info_dict = { + "cluster_id": nfs_clusterid, + } + + cluster_info = {"fs-manila": { + "virtual_ip": None, + "backend": [ + {"hostname": "fake-ceph-node-1", + "ip": "10.0.0.10", + "port": "1010"}, + {"hostname": "fake-ceph-node-2", + "ip": "10.0.0.11", + "port": "1011"} + ] + }} + + driver.rados_command.return_value = json.dumps(cluster_info) + + fake_cephfs_subvolume_path = "/foo/bar" + expected_export_locations = [{ + 'path': '10.0.0.10:/foo/bar', + 'is_admin_only': False, + 'metadata': {}, + 'preferred': True + }, { + 'path': '10.0.0.11:/foo/bar', + 'is_admin_only': False, + 'metadata': {}, + 'preferred': True + }] + if isinstance(val, list): + for ip in val: + expected_export_locations.append( + { + 'path': f'{ip}:/foo/bar', + 'is_admin_only': False, + 'metadata': {}, + 'preferred': False + } + ) + else: + expected_export_locations.append( + { + 'path': f'{val}:/foo/bar', + 'is_admin_only': False, + 'metadata': {}, + 'preferred': False + } + ) + + export_locations = ( + self._nfscluster_protocol_helper.get_export_locations( + self._share, fake_cephfs_subvolume_path)) + + driver.rados_command.assert_called_once_with( + self._rados_client, + cluster_info_prefix, cluster_info_dict) + + self.assertEqual(expected_export_locations, export_locations) + @ddt.ddt class CephFSDriverAltConfigTestCase(test.TestCase): diff --git a/releasenotes/notes/bug-2035137-ceph-nfs-set-preferred-export-location-d1f228a51df8c8b4.yaml b/releasenotes/notes/bug-2035137-ceph-nfs-set-preferred-export-location-d1f228a51df8c8b4.yaml new file mode 100644 index 0000000000..1a28008a6e --- /dev/null +++ b/releasenotes/notes/bug-2035137-ceph-nfs-set-preferred-export-location-d1f228a51df8c8b4.yaml @@ -0,0 +1,24 @@ +--- +features: + - | + It is now possible to configure `cephfs_ganesha_export_ips` (or + alternatively, `cephfs_ganesha_server_ip`) alongside + `cephfs_nfs_cluster_id`. Setting these options will allow the CephFS driver + to report additional export paths. These additional export paths will have + the "preferred" metadata key set to False. The export paths pertaining to + the NFS service host discovered by the driver will have the "preferred" + metadata key set to True. It is expected that administrators will configure + additional IP addresses when preparing to migrate from a standalone + NFS-Ganesha service to a NFS service cluster setup facilitated by the Ceph + orchestration service. Eventually, when the migration has completed, these + configuration options can be removed and the corresponding share export + path records will be dropped from Manila. Note that the CephFS driver will + not create or manipulate access rules within the NFS service configured via + `cephfs_ganesha_export_ips` or `cephfs_ganesha_server_ip`. +upgrades: + - | + In order to assist the user experience when migrating from a standalone + CephFS NFS (NFS-Ganesha) service to an NFS service created with the + Ceph Orchestrator, the CephFS driver allows configuring + `cephfs_ganesha_export_ips` (or alternatively, `cephfs_ganesha_server_ip`) + alongside `cephfs_nfs_cluster_id`.