Skip to content

Commit b11e6e2

Browse files
committed
Merge PR ceph#52859 into main
* refs/pull/52859/head: qa: test cases to make sure invalid paths don't get updated mgr/nfs: use helper to validate cephfs path mgr/nfs: validate path before updating a cephfs export mgr/nfs: add a helper to validate cephfs path Reviewed-by: Venky Shankar <[email protected]>
2 parents 40936ff + 2128fd0 commit b11e6e2

File tree

2 files changed

+87
-8
lines changed

2 files changed

+87
-8
lines changed

qa/tasks/cephfs/test_nfs.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,21 @@ def _nfs_export_apply(self, cluster, exports, raise_on_error=False):
411411
stdin=json.dumps(exports),
412412
stdout=StringIO(), stderr=StringIO())
413413

414+
def update_export(self, cluster_id, path, pseudo, fs_name):
415+
self.ctx.cluster.run(args=['ceph', 'nfs', 'export', 'apply',
416+
cluster_id, '-i', '-'],
417+
stdin=json.dumps({
418+
"path": path,
419+
"pseudo": pseudo,
420+
"squash": "none",
421+
"access_type": "rw",
422+
"protocols": [4],
423+
"fsal": {
424+
"name": "CEPH",
425+
"fs_name": fs_name
426+
}
427+
}))
428+
414429
def test_create_and_delete_cluster(self):
415430
'''
416431
Test successful creation and deletion of the nfs cluster.
@@ -1138,3 +1153,61 @@ def test_pseudo_path_in_json_response_when_updating_exports_failed(self):
11381153
finally:
11391154
self._delete_cluster_with_fs(self.fs_name, mnt_pt)
11401155
self.ctx.cluster.run(args=['rm', '-rf', f'{mnt_pt}'])
1156+
1157+
def test_cephfs_export_update_with_nonexistent_dir(self):
1158+
"""
1159+
Test that invalid path is not allowed while updating a CephFS
1160+
export.
1161+
"""
1162+
self._create_cluster_with_fs(self.fs_name)
1163+
self._create_export(export_id=1)
1164+
1165+
try:
1166+
self.update_export(self.cluster_id, "/not_existent_dir",
1167+
self.pseudo_path, self.fs_name)
1168+
except CommandFailedError as e:
1169+
if e.exitstatus != errno.ENOENT:
1170+
raise
1171+
1172+
self._delete_export()
1173+
self._delete_cluster_with_fs(self.fs_name)
1174+
1175+
def test_cephfs_export_update_at_non_dir_path(self):
1176+
"""
1177+
Test that non-directory path are not allowed while updating a CephFS
1178+
export.
1179+
"""
1180+
mnt_pt = '/mnt'
1181+
preserve_mode = self._sys_cmd(['stat', '-c', '%a', mnt_pt])
1182+
self._create_cluster_with_fs(self.fs_name, mnt_pt)
1183+
try:
1184+
self.ctx.cluster.run(args=['touch', f'{mnt_pt}/testfile'])
1185+
self._create_export(export_id=1)
1186+
1187+
# test at a file path
1188+
try:
1189+
self.update_export(self.cluster_id, "/testfile",
1190+
self.pseudo_path, self.fs_name)
1191+
except CommandFailedError as e:
1192+
if e.exitstatus != errno.ENOTDIR:
1193+
raise
1194+
1195+
# test at a symlink path
1196+
self.ctx.cluster.run(args=['mkdir', f'{mnt_pt}/testdir'])
1197+
self.ctx.cluster.run(args=['ln', '-s', f'{mnt_pt}/testdir',
1198+
f'{mnt_pt}/testdir_symlink'])
1199+
try:
1200+
self.update_export(self.cluster_id, "/testdir_symlink",
1201+
self.pseudo_path, self.fs_name)
1202+
except CommandFailedError as e:
1203+
if e.exitstatus != errno.ENOTDIR:
1204+
raise
1205+
1206+
# verify the path wasn't changed
1207+
export = json.loads(self._nfs_cmd("export", "ls",
1208+
self.cluster_id, "--detailed"))
1209+
self.assertEqual(export[0]["pseudo"], "/cephfs")
1210+
1211+
finally:
1212+
self.ctx.cluster.run(args=['rm', '-rf', f'{mnt_pt}/*'])
1213+
self._delete_cluster_with_fs(self.fs_name, mnt_pt, preserve_mode)

src/pybind/mgr/nfs/export.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ def normalize_path(path: str) -> str:
7171
return path
7272

7373

74+
def validate_cephfs_path(mgr: 'Module', fs_name: str, path: str) -> None:
75+
try:
76+
cephfs_path_is_dir(mgr, fs_name, path)
77+
except NotADirectoryError:
78+
raise NFSException(f"path {path} is not a dir", -errno.ENOTDIR)
79+
except cephfs.ObjectNotFound:
80+
raise NFSObjectNotFound(f"path {path} does not exist")
81+
except cephfs.Error as e:
82+
raise NFSException(e.args[1], -e.args[0])
83+
84+
7485
class NFSRados:
7586
def __init__(self, rados: 'Rados', namespace: str) -> None:
7687
self.rados = rados
@@ -675,6 +686,8 @@ def create_export_from_dict(self,
675686
if not check_fs(self.mgr, fs_name):
676687
raise FSNotFound(fs_name)
677688

689+
validate_cephfs_path(self.mgr, fs_name, path)
690+
678691
user_id = f"nfs.{cluster_id}.{ex_id}"
679692
if "user_id" in fsal and fsal["user_id"] != user_id:
680693
raise NFSInvalidOperation(f"export FSAL user_id must be '{user_id}'")
@@ -701,14 +714,7 @@ def create_cephfs_export(self,
701714
clients: list = [],
702715
sectype: Optional[List[str]] = None) -> Dict[str, Any]:
703716

704-
try:
705-
cephfs_path_is_dir(self.mgr, fs_name, path)
706-
except NotADirectoryError:
707-
raise NFSException(f"path {path} is not a dir", -errno.ENOTDIR)
708-
except cephfs.ObjectNotFound:
709-
raise NFSObjectNotFound(f"path {path} does not exist")
710-
except cephfs.Error as e:
711-
raise NFSException(e.args[1], -e.args[0])
717+
validate_cephfs_path(self.mgr, fs_name, path)
712718

713719
pseudo_path = normalize_path(pseudo_path)
714720

0 commit comments

Comments
 (0)