From 58ad31feb8f4af1f41e65edc8b03fc0b025a1d26 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Wed, 8 Jan 2025 09:51:32 -0500 Subject: [PATCH] pybind/mgr/volumes: wire up charmap for subvol/subvolgroup Signed-off-by: Patrick Donnelly (cherry picked from commit a6eeec80d77366fef71f1e13c037a3095823cbf5) --- .../mgr/volumes/fs/operations/charmap_util.py | 58 +++++++++++ src/pybind/mgr/volumes/fs/operations/group.py | 10 ++ .../mgr/volumes/fs/operations/template.py | 1 + .../fs/operations/versions/subvolume_base.py | 10 ++ src/pybind/mgr/volumes/fs/volume.py | 97 +++++++++++++++++++ src/pybind/mgr/volumes/module.py | 90 +++++++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 src/pybind/mgr/volumes/fs/operations/charmap_util.py diff --git a/src/pybind/mgr/volumes/fs/operations/charmap_util.py b/src/pybind/mgr/volumes/fs/operations/charmap_util.py new file mode 100644 index 00000000000..8051b1839c0 --- /dev/null +++ b/src/pybind/mgr/volumes/fs/operations/charmap_util.py @@ -0,0 +1,58 @@ +import errno + +import cephfs + +from ..exception import VolumeException +from ceph.utils import strtobool + +_charmap_type = { + "casesensitive": lambda x: int(strtobool(x)), + "normalization": lambda x: str(x), + "encoding": lambda x: str(x), +} + +def charmap_set(fs, path, setting, value): + """ + Set and get a charmap on a directory. + """ + + if setting not in _charmap_type: + raise VolumeException(-errno.EINVAL, f"charmap setting invalid") + + try: + value = _charmap_type[setting](value) + except ValueError: + raise VolumeException(-errno.EINVAL, f"charmap value wrong type: {setting}") + + try: + fs.setxattr(path, f"ceph.dir.{setting}", str(value).encode('utf-8'), 0) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + + try: + return fs.getxattr(path, f"ceph.dir.charmap").decode('utf-8') + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + +def charmap_rm(fs, path): + """ + Remove a charmap on a directory. + """ + + try: + fs.removexattr(path, "ceph.dir.charmap", 0) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + +def charmap_get(fs, path, setting): + """ + Get a charmap on a directory. + """ + + if setting not in _charmap_type and setting != 'charmap': + raise VolumeException(-errno.EINVAL, f"charmap setting invalid") + + try: + return fs.getxattr(path, f"ceph.dir.{setting}").decode('utf-8') + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) diff --git a/src/pybind/mgr/volumes/fs/operations/group.py b/src/pybind/mgr/volumes/fs/operations/group.py index efc10e0797a..60a734d942a 100644 --- a/src/pybind/mgr/volumes/fs/operations/group.py +++ b/src/pybind/mgr/volumes/fs/operations/group.py @@ -6,6 +6,7 @@ from contextlib import contextmanager import cephfs from .snapshot_util import mksnap, rmsnap +from .charmap_util import charmap_get, charmap_set, charmap_rm from .pin_util import pin from .template import GroupTemplate from ..fs_util import listdir, listsnaps, get_ancestor_xattr, create_base_dir, has_subdir @@ -78,6 +79,15 @@ class Group(GroupTemplate): def pin(self, pin_type, pin_setting): return pin(self.fs, self.path, pin_type, pin_setting) + def charmap_set(self, setting, value): + return charmap_set(self.fs, self.path, setting, value) + + def charmap_rm(self): + return charmap_rm(self.fs, self.path) + + def charmap_get(self, setting): + return charmap_get(self.fs, self.path, setting) + def create_snapshot(self, snapname): snappath = os.path.join(self.path, self.vol_spec.snapshot_dir_prefix.encode('utf-8'), diff --git a/src/pybind/mgr/volumes/fs/operations/template.py b/src/pybind/mgr/volumes/fs/operations/template.py index 2436863fd17..171363e8fd2 100644 --- a/src/pybind/mgr/volumes/fs/operations/template.py +++ b/src/pybind/mgr/volumes/fs/operations/template.py @@ -40,6 +40,7 @@ class SubvolumeOpType(Enum): CREATE = 'create' REMOVE = 'rm' REMOVE_FORCE = 'rm-force' + CHARMAP = 'charmap' PIN = 'pin' LIST = 'ls' GETPATH = 'getpath' 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 05df3101417..3aaf78e4648 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py @@ -9,6 +9,7 @@ from pathlib import Path import cephfs +from ..charmap_util import charmap_get, charmap_set, charmap_rm from ..pin_util import pin from .subvolume_attrs import SubvolumeTypes from .metadata_manager import MetadataManager @@ -342,6 +343,15 @@ class SubvolumeBase(object): def pin(self, pin_type, pin_setting): return pin(self.fs, self.base_path, pin_type, pin_setting) + def charmap_set(self, setting, value): + return charmap_set(self.fs, self.path, setting, value) + + def charmap_rm(self): + return charmap_rm(self.fs, self.path) + + def charmap_get(self, setting): + return charmap_get(self.fs, self.path, setting) + def init_config(self, version, subvolume_type, subvolume_path, subvolume_state): self.metadata_mgr.init(version, subvolume_type.value, diff --git a/src/pybind/mgr/volumes/fs/volume.py b/src/pybind/mgr/volumes/fs/volume.py index 2c592166f9c..b9465552b93 100644 --- a/src/pybind/mgr/volumes/fs/volume.py +++ b/src/pybind/mgr/volumes/fs/volume.py @@ -417,6 +417,58 @@ class VolumeClient(CephfsClient["Module"]): ret = self.volume_exception_to_retval(ve) return ret + def subvolume_charmap_set(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + setting = kwargs['setting'] + value = kwargs['value'] + 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.CHARMAP) as subvolume: + v = subvolume.charmap_set(setting, value) + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def subvolume_charmap_rm(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_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.CHARMAP) as subvolume: + subvolume.charmap_rm() + ret = 0, json.dumps({}), "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + + def subvolume_charmap_get(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + setting = kwargs['setting'] + 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.CHARMAP) as subvolume: + v = subvolume.charmap_get(setting) + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + def subvolume_getpath(self, **kwargs): ret = None volname = kwargs['vol_name'] @@ -1070,6 +1122,51 @@ class VolumeClient(CephfsClient["Module"]): ret = self.volume_exception_to_retval(ve) return ret + def subvolume_group_charmap_set(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + groupname = kwargs['group_name'] + setting = kwargs['setting'] + value = kwargs['value'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + v = group.charmap_set(setting, value) + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def subvolume_group_charmap_rm(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + groupname = kwargs['group_name'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + group.charmap_rm() + ret = 0, json.dumps({}), "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def subvolume_group_charmap_get(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + groupname = kwargs['group_name'] + setting = kwargs['setting'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + v = group.charmap_get(setting) + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + def subvolume_group_exists(self, **kwargs): volname = kwargs['vol_name'] ret = 0, "", "" diff --git a/src/pybind/mgr/volumes/module.py b/src/pybind/mgr/volumes/module.py index 6d768457f19..e8694709c53 100644 --- a/src/pybind/mgr/volumes/module.py +++ b/src/pybind/mgr/volumes/module.py @@ -331,6 +331,31 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): 'desc': "Set MDS pinning policy for subvolumegroup", 'perm': 'rw' }, + { + 'cmd': 'fs subvolumegroup charmap set' + ' name=vol_name,type=CephString' + ' name=group_name,type=CephString,req=true' + ' name=setting,type=CephChoices,strings=casesensitive|normalization|encoding' + ' name=value,type=CephString,req=true', + 'desc': "Set charmap settings for subvolumegroup", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolumegroup charmap rm' + ' name=vol_name,type=CephString' + ' name=group_name,type=CephString,req=true', + 'desc': "Remove charmap settings for subvolumegroup", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolumegroup charmap get' + ' name=vol_name,type=CephString' + ' name=group_name,type=CephString,req=true' + ' name=setting,type=CephChoices,strings=casesensitive|normalization|encoding,req=false', + 'desc': "Get charmap settings for subvolumegroup", + 'perm': 'rw' + }, + { 'cmd': 'fs subvolumegroup snapshot ls ' 'name=vol_name,type=CephString ' @@ -459,6 +484,33 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): 'desc': "Set MDS pinning policy for subvolume", 'perm': 'rw' }, + { + 'cmd': 'fs subvolume charmap set' + ' name=vol_name,type=CephString' + ' name=sub_name,type=CephString' + ' name=setting,type=CephChoices,strings=casesensitive|normalization|encoding' + ' name=value,type=CephString,req=true' + ' name=group_name,type=CephString,req=false', + 'desc': "Set charmap settings for subvolumegroup", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolume charmap rm' + ' name=vol_name,type=CephString' + ' name=sub_name,type=CephString' + ' name=group_name,type=CephString,req=false', + 'desc': "Remove charmap settings for subvolume", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolume charmap get' + ' name=vol_name,type=CephString' + ' name=sub_name,type=CephString' + ' name=setting,type=CephChoices,strings=casesensitive|normalization|encoding,req=false' + ' name=group_name,type=CephString,req=false', + 'desc': "Get charmap settings for subvolumegroup", + 'perm': 'rw' + }, { 'cmd': 'fs subvolume snapshot protect ' 'name=vol_name,type=CephString ' @@ -820,6 +872,23 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): group_name=cmd['group_name'], pin_type=cmd['pin_type'], pin_setting=cmd['pin_setting']) + @mgr_cmd_wrap + def _cmd_fs_subvolumegroup_charmap_set(self, inbuf, cmd): + return self.vc.subvolume_group_charmap_set(vol_name=cmd['vol_name'], + group_name=cmd['group_name'], + setting=cmd['setting'], + value=cmd['value']) + @mgr_cmd_wrap + def _cmd_fs_subvolumegroup_charmap_rm(self, inbuf, cmd): + return self.vc.subvolume_group_charmap_rm(vol_name=cmd['vol_name'], + group_name=cmd['group_name']) + + @mgr_cmd_wrap + def _cmd_fs_subvolumegroup_charmap_get(self, inbuf, cmd): + return self.vc.subvolume_group_charmap_get(vol_name=cmd['vol_name'], + group_name=cmd['group_name'], + setting=cmd.get('setting', 'charmap')) + @mgr_cmd_wrap def _cmd_fs_subvolumegroup_snapshot_create(self, inbuf, cmd): return self.vc.create_subvolume_group_snapshot(vol_name=cmd['vol_name'], @@ -912,6 +981,27 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): pin_setting=cmd['pin_setting'], group_name=cmd.get('group_name', None)) + @mgr_cmd_wrap + def _cmd_fs_subvolume_charmap_set(self, inbuf, cmd): + return self.vc.subvolume_charmap_set(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + setting=cmd['setting'], + value=cmd['value'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_charmap_rm(self, inbuf, cmd): + return self.vc.subvolume_charmap_rm(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_charmap_get(self, inbuf, cmd): + return self.vc.subvolume_charmap_get(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + setting=cmd.get('setting', 'charmap'), + group_name=cmd.get('group_name', None)) + @mgr_cmd_wrap def _cmd_fs_subvolume_snapshot_protect(self, inbuf, cmd): return self.vc.protect_subvolume_snapshot(vol_name=cmd['vol_name'], sub_name=cmd['sub_name'], -- 2.39.5