Skip to content

Commit e05d768

Browse files
Merge pull request ceph#62708 from rishabh-d-dave/vols-snap-path
mgr/vol: add command to get snapshot path Reviewed-by: Venky Shankar <[email protected]>
2 parents 11ce348 + a59b1fa commit e05d768

File tree

7 files changed

+168
-1
lines changed

7 files changed

+168
-1
lines changed

PendingReleaseNotes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107
`PutBucketPolicy`. Additionally, the root user will always have access to modify
108108
the bucket policy, even if the current policy explicitly denies access.
109109

110+
* CephFS: The ``ceph fs subvolume snapshot getpath`` command now allows users
111+
to get the path of a snapshot of a subvolume. If the snapshot is not present
112+
``ENOENT`` is returned.
113+
110114
* CephFS: The ``ceph fs volume create`` command now allows users to pass
111115
metadata and data pool names to be used for creating the volume. If either
112116
is not passed or if either is a non-empty pool, the command will abort.

doc/cephfs/fs-volumes.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,15 @@ otherwise fail (if the snapshot did not exist).
635635

636636
.. note:: if the last snapshot within a snapshot retained subvolume is removed, the subvolume is also removed
637637

638+
Fetching Path of a Snapshot of a Subvolume
639+
------------------------------------------
640+
Use a command of the following form to fetch the absolute path of a snapshot of
641+
a subvolume:
642+
643+
.. prompt:: base #
644+
645+
ceph fs subvolume snapshot getpath <volname> <subvol_name> <snap_name> [<group_name>]
646+
638647
Listing the Snapshots of a Subvolume
639648
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
640649

qa/tasks/cephfs/test_volumes.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,123 @@ def test_subvolume_snapshot_create_idempotence(self):
51755175
# verify trash dir is clean
51765176
self._wait_for_trash_empty()
51775177

5178+
def get_subvol_uuid(self, subvol_name, group_name=None):
5179+
'''
5180+
Return the UUID directory component obtained from the path of
5181+
subvolume.
5182+
'''
5183+
if group_name:
5184+
cmd = (f'fs subvolume getpath {self.volname} {subvol_name} '
5185+
f'{group_name}')
5186+
else:
5187+
cmd = f'fs subvolume getpath {self.volname} {subvol_name}'
5188+
5189+
subvol_path = self.get_ceph_cmd_stdout(cmd).strip()
5190+
5191+
subvol_uuid = os.path.basename(subvol_path)
5192+
return subvol_uuid
5193+
5194+
def test_snapshot_getpath(self):
5195+
'''
5196+
Test that "ceph fs subvolume snapshot getpath" command returns path to
5197+
the specified snapshot in the specified subvolume.
5198+
'''
5199+
subvol_name = self._gen_subvol_name()
5200+
snap_name = self._gen_subvol_snap_name()
5201+
5202+
self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name}')
5203+
sv_uuid = self.get_subvol_uuid(subvol_name)
5204+
self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
5205+
f'{subvol_name} {snap_name}')
5206+
5207+
snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
5208+
f'{self.volname} {subvol_name} '
5209+
f'{snap_name}').strip()
5210+
# expected snapshot path
5211+
exp_snap_path = os.path.join('/volumes', '_nogroup', subvol_name,
5212+
'.snap', snap_name, sv_uuid)
5213+
self.assertEqual(snap_path, exp_snap_path)
5214+
5215+
def test_snapshot_getpath_in_group(self):
5216+
'''
5217+
Test that "ceph fs subvolume snapshot getpath" command returns path to
5218+
the specified snapshot in the specified subvolume in the specified
5219+
group.
5220+
'''
5221+
subvol_name = self._gen_subvol_name()
5222+
group_name = self._gen_subvol_grp_name()
5223+
snap_name = self._gen_subvol_snap_name()
5224+
5225+
self.run_ceph_cmd(f'fs subvolumegroup create {self.volname} {group_name}')
5226+
self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name} '
5227+
f'{group_name}')
5228+
sv_uuid = self.get_subvol_uuid(subvol_name, group_name)
5229+
self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
5230+
f'{subvol_name} {snap_name} {group_name}')
5231+
5232+
snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
5233+
f'{self.volname} {subvol_name} '
5234+
f'{snap_name} {group_name}')\
5235+
.strip()
5236+
# expected snapshot path
5237+
exp_snap_path = os.path.join('/volumes', group_name, subvol_name,
5238+
'.snap', snap_name, sv_uuid)
5239+
self.assertEqual(snap_path, exp_snap_path)
5240+
5241+
def test_snapshot_getpath_on_retained_subvol(self):
5242+
'''
5243+
Test that "ceph fs subvolume snapshot getpath" command returns path to
5244+
the specified snapshot in the specified subvolume that was deleted but
5245+
snapshots on which is retained.
5246+
'''
5247+
subvol_name = self._gen_subvol_name()
5248+
snap_name = self._gen_subvol_snap_name()
5249+
5250+
self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name}')
5251+
sv_uuid = self.get_subvol_uuid(subvol_name)
5252+
self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
5253+
f'{subvol_name} {snap_name}')
5254+
self.run_ceph_cmd(f'fs subvolume rm {self.volname} {subvol_name} '
5255+
'--retain-snapshots')
5256+
5257+
snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
5258+
f'{self.volname} {subvol_name} '
5259+
f'{snap_name}').strip()
5260+
5261+
# expected snapshot path
5262+
exp_snap_path = os.path.join('/volumes', '_nogroup', subvol_name,
5263+
'.snap', snap_name, sv_uuid)
5264+
self.assertEqual(snap_path, exp_snap_path)
5265+
5266+
def test_snapshot_getpath_on_retained_subvol_in_group(self):
5267+
'''
5268+
Test that "ceph fs subvolume snapshot getpath" command returns path to
5269+
the specified snapshot in the specified subvolume that was deleted but
5270+
snapshots on which is retained. And the deleted subvolume is located on
5271+
a non-default group.
5272+
'''
5273+
subvol_name = self._gen_subvol_name()
5274+
group_name = self._gen_subvol_grp_name()
5275+
snap_name = self._gen_subvol_snap_name()
5276+
5277+
self.run_ceph_cmd(f'fs subvolumegroup create {self.volname} {group_name}')
5278+
self.run_ceph_cmd(f'fs subvolume create {self.volname} {subvol_name} '
5279+
f'{group_name}')
5280+
sv_uuid = self.get_subvol_uuid(subvol_name, group_name)
5281+
self.run_ceph_cmd(f'fs subvolume snapshot create {self.volname} '
5282+
f'{subvol_name} {snap_name} {group_name}')
5283+
self.run_ceph_cmd(f'fs subvolume rm {self.volname} {subvol_name} '
5284+
f'{group_name} --retain-snapshots')
5285+
5286+
snap_path = self.get_ceph_cmd_stdout(f'fs subvolume snapshot getpath '
5287+
f'{self.volname} {subvol_name} '
5288+
f'{snap_name} {group_name}')\
5289+
.strip()
5290+
# expected snapshot path
5291+
exp_snap_path = os.path.join('/volumes', group_name, subvol_name,
5292+
'.snap', snap_name, sv_uuid)
5293+
self.assertEqual(snap_path, exp_snap_path)
5294+
51785295
def test_subvolume_snapshot_info(self):
51795296

51805297
"""

src/pybind/mgr/volumes/fs/operations/template.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class SubvolumeOpType(Enum):
4949
SNAP_CREATE = 'snap-create'
5050
SNAP_REMOVE = 'snap-rm'
5151
SNAP_LIST = 'snap-ls'
52+
SNAP_GETPATH = 'snap-getpath'
5253
SNAP_INFO = 'snap-info'
5354
SNAP_PROTECT = 'snap-protect'
5455
SNAP_UNPROTECT = 'snap-unprotect'

src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def allowed_ops_by_state(self, vol_state):
282282
SubvolumeOpType.INFO,
283283
SubvolumeOpType.SNAP_REMOVE,
284284
SubvolumeOpType.SNAP_LIST,
285+
SubvolumeOpType.SNAP_GETPATH,
285286
SubvolumeOpType.SNAP_INFO,
286287
SubvolumeOpType.SNAP_PROTECT,
287288
SubvolumeOpType.SNAP_UNPROTECT,

src/pybind/mgr/volumes/fs/volume.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
list_volumes, open_volume, get_pool_names, get_pool_ids, \
2323
get_pending_subvol_deletions_count, get_all_pending_clones_count
2424
from .operations.subvolume import open_subvol, create_subvol, remove_subvol, \
25-
create_clone, open_subvol_in_group
25+
create_clone, open_subvol_in_group, open_subvol_in_vol
2626

2727
from .vol_spec import VolSpec
2828
from .exception import VolumeException, ClusterError, ClusterTimeout, \
@@ -789,6 +789,23 @@ def subvolume_snapshot_info(self, **kwargs):
789789
ret = self.volume_exception_to_retval(ve)
790790
return ret
791791

792+
def subvolume_snapshot_getpath(self, **kwargs):
793+
ret = 0, "", ""
794+
volname = kwargs['vol_name']
795+
subvolname = kwargs['sub_name']
796+
snapname = kwargs['snap_name']
797+
groupname = kwargs['group_name']
798+
799+
try:
800+
with open_subvol_in_vol(self, self.volspec, volname, groupname, subvolname,
801+
SubvolumeOpType.SNAP_GETPATH) \
802+
as (vol, group, subvol):
803+
snap_path = subvol.snapshot_data_path(snapname)
804+
ret = 0, snap_path.decode("utf-8"), ""
805+
except VolumeException as ve:
806+
ret = self.volume_exception_to_retval(ve)
807+
return ret
808+
792809
def set_subvolume_snapshot_metadata(self, **kwargs):
793810
ret = 0, "", ""
794811
volname = kwargs['vol_name']

src/pybind/mgr/volumes/module.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,17 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
468468
"and optionally, in a specific subvolume group",
469469
'perm': 'rw'
470470
},
471+
{
472+
'cmd': 'fs subvolume snapshot getpath '
473+
'name=vol_name,type=CephString '
474+
'name=sub_name,type=CephString '
475+
'name=snap_name,type=CephString '
476+
'name=group_name,type=CephString,req=false ',
477+
'desc': 'Get path for a snapshot of a CephFS subvolume located in '
478+
'a specific volume, and optionally, in a specific '
479+
'subvolume group',
480+
'perm': 'r'
481+
},
471482
{
472483
'cmd': 'fs subvolume resize '
473484
'name=vol_name,type=CephString '
@@ -999,6 +1010,13 @@ def _cmd_fs_subvolume_snapshot_ls(self, inbuf, cmd):
9991010
sub_name=cmd['sub_name'],
10001011
group_name=cmd.get('group_name', None))
10011012

1013+
@mgr_cmd_wrap
1014+
def _cmd_fs_subvolume_snapshot_getpath(self, inbuf, cmd):
1015+
return self.vc.subvolume_snapshot_getpath(vol_name=cmd['vol_name'],
1016+
sub_name=cmd['sub_name'],
1017+
snap_name=cmd['snap_name'],
1018+
group_name=cmd.get('group_name', None))
1019+
10021020
@mgr_cmd_wrap
10031021
def _cmd_fs_subvolume_resize(self, inbuf, cmd):
10041022
return self.vc.resize_subvolume(vol_name=cmd['vol_name'], sub_name=cmd['sub_name'],

0 commit comments

Comments
 (0)