From: Nikhilkumar Shelke Date: Wed, 27 Apr 2022 16:20:33 +0000 (+0530) Subject: mgr/volumes: set, get, list and remove custom metadata for snapshot X-Git-Tag: v17.2.1~6^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b683d5fd07f6391b4e73d72128c77ab89789e270;p=ceph.git mgr/volumes: set, get, list and remove custom metadata for snapshot If CephFS in ODF configured in external mode, user like to use subvolume snapshot metadata to store some Openshift specific information, as the PVC/PV/namespace the subvolumes/snapshot are coming from. For RBD volumes, it's possible to add metadata information to the images using the 'rbd image-meta' command. However, this feature is not available for CephFS volumes. We'd like to request this capability. Adding following commands: ceph fs subvolume snapshot metadata set [] ceph fs subvolume snapshot metadata get [] ceph fs subvolume snapshot metadata ls [] ceph fs subvolume snapshot metadata rm [] [--force] Fixes: https://tracker.ceph.com/issues/55401 Signed-off-by: Nikhilkumar Shelke (cherry picked from commit 559222cfe8d552cd2d7aef7361de4140820ae74a) --- diff --git a/src/pybind/mgr/volumes/fs/operations/template.py b/src/pybind/mgr/volumes/fs/operations/template.py index 23ef2aba6f91..eb55bd743251 100644 --- a/src/pybind/mgr/volumes/fs/operations/template.py +++ b/src/pybind/mgr/volumes/fs/operations/template.py @@ -60,10 +60,14 @@ class SubvolumeOpType(Enum): DENY_ACCESS = 'deny-access' AUTH_LIST = 'auth-list' EVICT = 'evict' - USER_METADATA_SET = 'metadata-set' - USER_METADATA_GET = 'metadata-get' - USER_METADATA_LIST = 'metadata-ls' - USER_METADATA_REMOVE = 'metadata-rm' + USER_METADATA_SET = 'user-metadata-set' + USER_METADATA_GET = 'user-metadata-get' + USER_METADATA_LIST = 'user-metadata-ls' + USER_METADATA_REMOVE = 'user-metadata-rm' + SNAP_METADATA_SET = 'snap-metadata-set' + SNAP_METADATA_GET = 'snap-metadata-get' + SNAP_METADATA_LIST = 'snap-metadata-ls' + SNAP_METADATA_REMOVE = 'snap-metadata-rm' class SubvolumeTemplate(object): VERSION = None # type: int diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py index 73c0d29d0cd4..f7aa2ec81586 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py @@ -433,3 +433,36 @@ class SubvolumeBase(object): if me.errno == -errno.ENOENT: raise VolumeException(-errno.ENOENT, "subvolume metadata not does not exist") raise VolumeException(-me.args[0], me.args[1]) + + def get_snap_section_name(self, snapname): + section = "SNAP_METADATA" + "_" + snapname; + return section; + + def set_snapshot_metadata(self, snapname, keyname, value): + section = self.get_snap_section_name(snapname) + self.metadata_mgr.add_section(section) + self.metadata_mgr.update_section(section, keyname, str(value)) + self.metadata_mgr.flush() + + def get_snapshot_metadata(self, snapname, keyname): + try: + value = self.metadata_mgr.get_option(self.get_snap_section_name(snapname), keyname) + except MetadataMgrException as me: + if me.errno == -errno.ENOENT: + raise VolumeException(-errno.ENOENT, "key '{0}' does not exist.".format(keyname)) + raise VolumeException(-me.args[0], me.args[1]) + return value + + def list_snapshot_metadata(self, snapname): + return self.metadata_mgr.list_all_options_from_section(self.get_snap_section_name(snapname)) + + def remove_snapshot_metadata(self, snapname, keyname): + try: + ret = self.metadata_mgr.remove_option(self.get_snap_section_name(snapname), keyname) + if not ret: + raise VolumeException(-errno.ENOENT, "key '{0}' does not exist.".format(keyname)) + self.metadata_mgr.flush() + except MetadataMgrException as me: + if me.errno == -errno.ENOENT: + raise VolumeException(-errno.ENOENT, "snapshot metadata not does not exist") + raise VolumeException(-me.args[0], me.args[1]) diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py index 542c860e897d..8c98b3736222 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py @@ -743,6 +743,8 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): raise VolumeException(-errno.EAGAIN, "snapshot '{0}' has pending clones".format(snapname)) snappath = self.snapshot_path(snapname) rmsnap(self.fs, snappath) + self.metadata_mgr.remove_section(self.get_snap_section_name(snapname)) + self.metadata_mgr.flush() def snapshot_info(self, snapname): if is_inherited_snap(snapname): diff --git a/src/pybind/mgr/volumes/fs/volume.py b/src/pybind/mgr/volumes/fs/volume.py index 47e95db6a1a4..18c5da222fe1 100644 --- a/src/pybind/mgr/volumes/fs/volume.py +++ b/src/pybind/mgr/volumes/fs/volume.py @@ -522,6 +522,86 @@ class VolumeClient(CephfsClient["Module"]): ret = self.volume_exception_to_retval(ve) return ret + def set_subvolume_snapshot_metadata(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + snapname = kwargs['snap_name'] + groupname = kwargs['group_name'] + keyname = kwargs['key_name'] + value = kwargs['value'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, SubvolumeOpType.SNAP_METADATA_SET) as subvolume: + if not snapname.encode('utf-8') in subvolume.list_snapshots(): + raise VolumeException(-errno.ENOENT, "snapshot '{0}' does not exist".format(snapname)) + subvolume.set_snapshot_metadata(snapname, keyname, value) + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def get_subvolume_snapshot_metadata(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + snapname = kwargs['snap_name'] + groupname = kwargs['group_name'] + keyname = kwargs['key_name'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, SubvolumeOpType.SNAP_METADATA_GET) as subvolume: + if not snapname.encode('utf-8') in subvolume.list_snapshots(): + raise VolumeException(-errno.ENOENT, "snapshot '{0}' does not exist".format(snapname)) + value = subvolume.get_snapshot_metadata(snapname, keyname) + ret = 0, value, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def list_subvolume_snapshot_metadata(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + snapname = kwargs['snap_name'] + groupname = kwargs['group_name'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, SubvolumeOpType.SNAP_METADATA_LIST) as subvolume: + if not snapname.encode('utf-8') in subvolume.list_snapshots(): + raise VolumeException(-errno.ENOENT, "snapshot '{0}' does not exist".format(snapname)) + snap_metadata_dict = subvolume.list_snapshot_metadata(snapname) + ret = 0, json.dumps(snap_metadata_dict, indent=4, sort_keys=True), "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def remove_subvolume_snapshot_metadata(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + snapname = kwargs['snap_name'] + groupname = kwargs['group_name'] + keyname = kwargs['key_name'] + force = kwargs['force'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, SubvolumeOpType.SNAP_METADATA_REMOVE) as subvolume: + if not snapname.encode('utf-8') in subvolume.list_snapshots(): + raise VolumeException(-errno.ENOENT, "snapshot '{0}' does not exist".format(snapname)) + subvolume.remove_snapshot_metadata(snapname, keyname) + except VolumeException as ve: + if not (ve.errno == -errno.ENOENT and force): + ret = self.volume_exception_to_retval(ve) + return ret + def list_subvolume_snapshots(self, **kwargs): ret = 0, "", "" volname = kwargs['vol_name'] diff --git a/src/pybind/mgr/volumes/module.py b/src/pybind/mgr/volumes/module.py index e66c107abf37..eb4a82f16565 100644 --- a/src/pybind/mgr/volumes/module.py +++ b/src/pybind/mgr/volumes/module.py @@ -291,10 +291,55 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): 'name=sub_name,type=CephString ' 'name=snap_name,type=CephString ' 'name=group_name,type=CephString,req=false ', - 'desc': "Get the metadata of a CephFS subvolume snapshot " + 'desc': "Get the information of a CephFS subvolume snapshot " "and optionally, in a specific subvolume group", 'perm': 'r' }, + { + 'cmd': 'fs subvolume snapshot metadata set ' + 'name=vol_name,type=CephString ' + 'name=sub_name,type=CephString ' + 'name=snap_name,type=CephString ' + 'name=key_name,type=CephString ' + 'name=value,type=CephString ' + 'name=group_name,type=CephString,req=false ', + 'desc': "Set custom metadata (key-value) for a CephFS subvolume snapshot in a volume, " + "and optionally, in a specific subvolume group", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolume snapshot metadata get ' + 'name=vol_name,type=CephString ' + 'name=sub_name,type=CephString ' + 'name=snap_name,type=CephString ' + 'name=key_name,type=CephString ' + 'name=group_name,type=CephString,req=false ', + 'desc': "Get custom metadata associated with the key of a CephFS subvolume snapshot in a volume, " + "and optionally, in a specific subvolume group", + 'perm': 'r' + }, + { + 'cmd': 'fs subvolume snapshot metadata ls ' + 'name=vol_name,type=CephString ' + 'name=sub_name,type=CephString ' + 'name=snap_name,type=CephString ' + 'name=group_name,type=CephString,req=false ', + 'desc': "List custom metadata (key-value pairs) of a CephFS subvolume snapshot in a volume, " + "and optionally, in a specific subvolume group", + 'perm': 'r' + }, + { + 'cmd': 'fs subvolume snapshot metadata rm ' + 'name=vol_name,type=CephString ' + 'name=sub_name,type=CephString ' + 'name=snap_name,type=CephString ' + 'name=key_name,type=CephString ' + 'name=group_name,type=CephString,req=false ' + 'name=force,type=CephBool,req=false ', + 'desc': "Remove custom metadata (key-value) associated with the key of a CephFS subvolume snapshot in a volume, " + "and optionally, in a specific subvolume group", + 'perm': 'rw' + }, { 'cmd': 'fs subvolume snapshot rm ' 'name=vol_name,type=CephString ' @@ -659,6 +704,39 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): snap_name=cmd['snap_name'], group_name=cmd.get('group_name', None)) + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_metadata_set(self, inbuf, cmd): + return self.vc.set_subvolume_snapshot_metadata(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + snap_name=cmd['snap_name'], + key_name=cmd['key_name'], + value=cmd['value'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_metadata_get(self, inbuf, cmd): + return self.vc.get_subvolume_snapshot_metadata(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + snap_name=cmd['snap_name'], + key_name=cmd['key_name'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_metadata_ls(self, inbuf, cmd): + return self.vc.list_subvolume_snapshot_metadata(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + snap_name=cmd['snap_name'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_metadata_rm(self, inbuf, cmd): + return self.vc.remove_subvolume_snapshot_metadata(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + snap_name=cmd['snap_name'], + key_name=cmd['key_name'], + group_name=cmd.get('group_name', None), + force=cmd.get('force', False)) + @mgr_cmd_wrap def _cmd_fs_subvolume_snapshot_ls(self, inbuf, cmd): return self.vc.list_subvolume_snapshots(vol_name=cmd['vol_name'],