From 9eac44efc6f41a85f114284b8a6c7f5a3a7e8fa5 Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Tue, 28 Apr 2020 00:01:33 +0530 Subject: [PATCH] mgr/volumes: Create subvolume with isolated rados namespace 1. Add --namespace-isolated option to 'subvolume create' command to create subvolume in a separate RADOS namespace 2. Add "pool_namespace" field to 'subvolume info' command which displays the rados namespace if set else empty string Fixes: https://tracker.ceph.com/issues/45289 Signed-off-by: Kotresh HR (cherry picked from commit 7396880d4096b3a2a813b8ebcdcdf3082ee98b23) --- doc/cephfs/fs-volumes.rst | 8 +++--- qa/tasks/cephfs/test_volumes.py | 27 +++++++++++++++++-- .../fs/operations/versions/subvolume_base.py | 4 ++- src/pybind/mgr/volumes/fs/volume.py | 6 +++-- src/pybind/mgr/volumes/module.py | 9 ++++--- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/doc/cephfs/fs-volumes.rst b/doc/cephfs/fs-volumes.rst index f602cc1063ac..2625a59d5b2a 100644 --- a/doc/cephfs/fs-volumes.rst +++ b/doc/cephfs/fs-volumes.rst @@ -115,15 +115,16 @@ FS Subvolumes Create a subvolume using:: - $ ceph fs subvolume create [--size --group_name --pool_layout --uid --gid --mode ] + $ ceph fs subvolume create [--size --group_name --pool_layout --uid --gid --mode --namespace-isolated] The command succeeds even if the subvolume already exists. When creating a subvolume you can specify its subvolume group, data pool layout, uid, gid, file mode in octal numerals, and size in bytes. The size of the subvolume is -specified by setting a quota on it (see :doc:`/cephfs/quota`). By default a -subvolume is created within the default subvolume group, and with an octal file +specified by setting a quota on it (see :doc:`/cephfs/quota`). The subvolume can be +created in a separate RADOS namespace by specifying --namespace-isolated option. By +default a subvolume is created within the default subvolume group, and with an octal file mode '755', uid of its subvolume group, gid of its subvolume group, data pool layout of its parent directory and no size limit. @@ -172,6 +173,7 @@ The output format is json and contains fields as follows. * data_pool: data pool the subvolume belongs to * path: absolute path of a subvolume * type: subvolume type indicating whether it's clone or subvolume +* pool_namespace: RADOS namespace of the subvolume List subvolumes using:: diff --git a/qa/tasks/cephfs/test_volumes.py b/qa/tasks/cephfs/test_volumes.py index 8a60bf75e6f4..5c0f1e9815d3 100644 --- a/qa/tasks/cephfs/test_volumes.py +++ b/qa/tasks/cephfs/test_volumes.py @@ -584,6 +584,26 @@ class TestVolumes(CephFSTestCase): # verify trash dir is clean self._wait_for_trash_empty() + def test_subvolume_create_isolated_namespace(self): + """ + Create subvolume in separate rados namespace + """ + + # create subvolume + subvolume = self._generate_random_subvolume_name() + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--namespace-isolated") + + # get subvolume metadata + subvol_info = json.loads(self._get_subvolume_info(self.volname, subvolume)) + self.assertNotEqual(len(subvol_info), 0) + self.assertEqual(subvol_info["pool_namespace"], "fsvolumens_" + subvolume) + + # remove subvolumes + self._fs_cmd("subvolume", "rm", self.volname, subvolume) + + # verify trash dir is clean + self._wait_for_trash_empty() + def test_subvolume_create_with_invalid_data_pool_layout(self): subvolume = self._generate_random_subvolume_name() data_pool = "invalid_pool" @@ -763,7 +783,8 @@ class TestVolumes(CephFSTestCase): # tests the 'fs subvolume info' command subvol_md = ["atime", "bytes_pcent", "bytes_quota", "bytes_used", "created_at", "ctime", - "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "type", "uid"] + "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "pool_namespace", + "type", "uid"] # create subvolume subvolume = self._generate_random_subvolume_name() @@ -782,6 +803,7 @@ class TestVolumes(CephFSTestCase): if subvol_info["bytes_quota"] != "infinite": raise RuntimeError("bytes_quota should be set to infinite if quota is not set") + self.assertEqual(subvol_info["pool_namespace"], "") nsize = self.DEFAULT_FILE_SIZE*1024*1024 try: @@ -812,7 +834,8 @@ class TestVolumes(CephFSTestCase): # tests the 'fs subvolume info' command for a clone subvol_md = ["atime", "bytes_pcent", "bytes_quota", "bytes_used", "created_at", "ctime", - "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "type", "uid"] + "data_pool", "gid", "mode", "mon_addrs", "mtime", "path", "pool_namespace", + "type", "uid"] subvolume = self._generate_random_subvolume_name() snapshot = self._generate_random_snapshot_name() 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 dd0aec4d68b1..30c9235a8718 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py @@ -248,6 +248,7 @@ class SubvolumeBase(object): try: data_pool = self.fs.getxattr(subvolpath, 'ceph.dir.layout.pool').decode('utf-8') + pool_namespace = self.fs.getxattr(subvolpath, 'ceph.dir.layout.pool_namespace').decode('utf-8') except cephfs.Error as e: raise VolumeException(-e.args[0], e.args[1]) @@ -255,4 +256,5 @@ class SubvolumeBase(object): 'atime': str(st["atime"]), 'mtime': str(st["mtime"]), 'ctime': str(st["ctime"]), 'mode': int(st["mode"]), 'data_pool': data_pool, 'created_at': str(st["btime"]), 'bytes_quota': "infinite" if nsize == 0 else nsize, 'bytes_used': int(usedbytes), - 'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0)} + 'bytes_pcent': "undefined" if nsize == 0 else '{0:.2f}'.format((float(usedbytes) / nsize) * 100.0), + 'pool_namespace': pool_namespace} diff --git a/src/pybind/mgr/volumes/fs/volume.py b/src/pybind/mgr/volumes/fs/volume.py index f29c1648114d..87be3145bba9 100644 --- a/src/pybind/mgr/volumes/fs/volume.py +++ b/src/pybind/mgr/volumes/fs/volume.py @@ -116,11 +116,12 @@ class VolumeClient(object): uid = kwargs['uid'] gid = kwargs['gid'] mode = kwargs['mode'] + isolate_nspace = kwargs['namespace_isolated'] oct_mode = octal_str_to_decimal_int(mode) try: create_subvol( - fs_handle, self.volspec, group, subvolname, size, False, pool, oct_mode, uid, gid) + fs_handle, self.volspec, group, subvolname, size, isolate_nspace, pool, oct_mode, uid, gid) except VolumeException as ve: # kick the purge threads for async removal -- note that this # assumes that the subvolume is moved to trashcan for cleanup on error. @@ -136,6 +137,7 @@ class VolumeClient(object): pool = kwargs['pool_layout'] uid = kwargs['uid'] gid = kwargs['gid'] + isolate_nspace = kwargs['namespace_isolated'] try: with open_volume(self, volname) as fs_handle: @@ -145,7 +147,7 @@ class VolumeClient(object): # idempotent creation -- valid. Attributes set is supported. uid = uid if uid else subvolume.uid gid = gid if gid else subvolume.gid - subvolume.set_attrs(subvolume.path, size, False, pool, uid, gid) + subvolume.set_attrs(subvolume.path, size, isolate_nspace, pool, uid, gid) except VolumeException as ve: if ve.errno == -errno.ENOENT: self._create_subvolume(fs_handle, volname, group, subvolname, **kwargs) diff --git a/src/pybind/mgr/volumes/module.py b/src/pybind/mgr/volumes/module.py index bbb1896e0c73..a6dfb1026d74 100644 --- a/src/pybind/mgr/volumes/module.py +++ b/src/pybind/mgr/volumes/module.py @@ -69,10 +69,12 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): 'name=pool_layout,type=CephString,req=false ' 'name=uid,type=CephInt,req=false ' 'name=gid,type=CephInt,req=false ' - 'name=mode,type=CephString,req=false ', + 'name=mode,type=CephString,req=false ' + 'name=namespace_isolated,type=CephBool,req=false ', 'desc': "Create a CephFS subvolume in a volume, and optionally, " "with a specific size (in bytes), a specific data pool layout, " - "a specific mode, and in a specific subvolume group", + "a specific mode, in a specific subvolume group and in separate " + "RADOS namespace", 'perm': 'rw' }, { @@ -302,7 +304,8 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): pool_layout=cmd.get('pool_layout', None), uid=cmd.get('uid', None), gid=cmd.get('gid', None), - mode=cmd.get('mode', '755')) + mode=cmd.get('mode', '755'), + namespace_isolated=cmd.get('namespace_isolated', False)) def _cmd_fs_subvolume_rm(self, inbuf, cmd): """ -- 2.47.3