Skip to content

Commit f38fcbc

Browse files
qa/cephfs: add tests for config option pause_purging
Setting MGR config option mgr/volumes/pause_purging to true halts all ongoing purges and allows no new purging to begin until this option is changed to false. Add tests for this. Signed-off-by: Rishabh Dave <[email protected]>
1 parent 9582b9b commit f38fcbc

File tree

2 files changed

+189
-1
lines changed

2 files changed

+189
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
tasks:
2+
- cephfs_test_runner:
3+
fail_on_skip: false
4+
modules:
5+
- tasks.cephfs.test_volumes.TestPausePurging

qa/tasks/cephfs/test_volumes.py

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from tasks.cephfs.cephfs_test_case import CephFSTestCase
1515
from tasks.cephfs.fuse_mount import FuseMount
1616
from teuthology.contextutil import safe_while
17-
from teuthology.exceptions import CommandFailedError
17+
from teuthology.exceptions import CommandFailedError, MaxWhileTries
1818

1919
log = logging.getLogger(__name__)
2020

@@ -4437,6 +4437,189 @@ def test_create_when_subvol_group_name_is_too_long(self):
44374437
errmsgs='Error ENAMETOOLONG: use shorter group or subvol name, '
44384438
'combination of both should be less than 249 characters')
44394439

4440+
class TestPausePurging(TestVolumesHelper):
4441+
'''
4442+
Tests related to config "mgr/volumes/pause_purging".
4443+
'''
4444+
4445+
CONF_OPT = 'mgr/volumes/pause_purging'
4446+
4447+
def tearDown(self):
4448+
# every test will change value of this config option as per its need.
4449+
# assure that this config option's default value is re-stored during
4450+
# tearDown() so that there's zero chance that it interferes with next
4451+
# test.
4452+
self.config_set('mgr', self.CONF_OPT, False)
4453+
4454+
# ensure purge threads have no jobs left from previous test so that
4455+
# next test doesn't have to face unnecessary complications.
4456+
self._wait_for_trash_empty()
4457+
4458+
super().tearDown()
4459+
4460+
def _get_sv_path(self, v, sv):
4461+
sv_path = self.get_ceph_cmd_stdout(f'fs subvolume getpath {v} {sv}')
4462+
sv_path = sv_path.strip()
4463+
# delete slash at the beginning of path
4464+
sv_path = sv_path[1:]
4465+
4466+
sv_path = os.path.join(self.mount_a.mountpoint, sv_path)
4467+
return sv_path
4468+
4469+
def _assert_sv_is_absent_in_trash(self, sv, sv_path, sv_files):
4470+
uuid = self.mount_a.get_shell_stdout('sudo ls volumes/_deleting').\
4471+
strip()
4472+
4473+
trash_sv_path = sv_path.replace('_nogroup', f'_deleting/{uuid}')
4474+
trash_sv_path = trash_sv_path.replace(sv, '')
4475+
4476+
try:
4477+
sv_files_new = self.mount_a.get_shell_stdout(
4478+
f'sudo ls {trash_sv_path}')
4479+
except CommandFailedError as cfe:
4480+
# in case dir for subvol including files in it are deleted
4481+
self.assertEqual(cfe.exitstatus, 2)
4482+
return
4483+
4484+
# in case dir for subvol is undeleted yet (but files inside it are).
4485+
for filename in sv_files:
4486+
self.assertNotIn(filename, sv_files_new)
4487+
4488+
def _assert_trashed_sv_is_unpurged(self, sv, sv_path, sv_files):
4489+
uuid = self.mount_a.get_shell_stdout('sudo ls volumes/_deleting').\
4490+
strip()
4491+
4492+
trash_sv_path = sv_path.replace('_nogroup', f'_deleting/{uuid}')
4493+
trash_sv_path = trash_sv_path.replace(sv, '')
4494+
sv_files_new = self.mount_a.get_shell_stdout(f'sudo ls {trash_sv_path}').\
4495+
strip()
4496+
4497+
for filename in sv_files:
4498+
self.assertIn(filename, sv_files_new)
4499+
4500+
def test_when_paused_subvol_is_trashed_but_stays_unpurged(self):
4501+
'''
4502+
Test that when MGR config option mgr/volumes/pause_purging is
4503+
set to true, running "ceph fs subvolume rm" will move the subvolume
4504+
to trash but not purge it, that is delete the subvolume from trash.
4505+
'''
4506+
v = self.volname
4507+
sv = 'sv1'
4508+
4509+
self.run_ceph_cmd(f'fs subvolume create {v} {sv} --mode=777')
4510+
4511+
self.config_set('mgr', self.CONF_OPT, True)
4512+
sv_path = self._get_sv_path(v, sv)
4513+
self._do_subvolume_io(sv, number_of_files=10)
4514+
sv_files = self.mount_a.get_shell_stdout(f'sudo ls {sv_path}').\
4515+
strip().split('\n')
4516+
4517+
self.run_ceph_cmd(f'fs subvolume rm {v} {sv}')
4518+
# wait for a bit to ensure that trashed subvolume is not picked by
4519+
# purged threads eventually.
4520+
with safe_while(tries=1, sleep=7) as proceed:
4521+
try:
4522+
while proceed():
4523+
self._assert_trashed_sv_is_unpurged(sv, sv_path, sv_files)
4524+
except MaxWhileTries:
4525+
pass
4526+
4527+
def test_on_resuming_unpurged_subvol_is_purged(self):
4528+
'''
4529+
Test that when MGR config option mgr/volumes/pause_purging is
4530+
is set to false, trashed but unpurged subvolume is purged (fully).
4531+
'''
4532+
v = self.volname
4533+
sv = 'sv1'
4534+
4535+
self.run_ceph_cmd(f'fs subvolume create {v} {sv} --mode=777')
4536+
self.config_set('mgr', self.CONF_OPT, True)
4537+
sv_path = self._get_sv_path(v, sv)
4538+
self._do_subvolume_io(sv, number_of_files=10)
4539+
sv_files = self.mount_a.get_shell_stdout(f'sudo ls {sv_path}').\
4540+
strip().split('\n')
4541+
4542+
self.run_ceph_cmd(f'fs subvolume rm {v} {sv}')
4543+
# wait for a bit to ensure that trashed subvolume is not picked by
4544+
# purged threads eventually.
4545+
with safe_while(tries=1, sleep=7) as proceed:
4546+
try:
4547+
while proceed():
4548+
self._assert_trashed_sv_is_unpurged(sv, sv_path, sv_files)
4549+
except MaxWhileTries:
4550+
pass
4551+
4552+
# XXX actual test here: test that unpurged subvol is purged
4553+
self.config_set('mgr', self.CONF_OPT, False)
4554+
self._wait_for_trash_empty()
4555+
4556+
def _get_trashed_sv_path(self, sv, sv_path):
4557+
uuid = self.mount_a.get_shell_stdout('sudo ls volumes/_deleting').\
4558+
strip()
4559+
4560+
trashed_sv_path = sv_path.replace('_nogroup', f'_deleting/{uuid}')
4561+
trashed_sv_path = trashed_sv_path.replace(sv, '')
4562+
return trashed_sv_path
4563+
4564+
def _get_num_of_files_in_trashed_sv(self, trashed_sv_path):
4565+
trashed_sv_files = self.mount_a.get_shell_stdout(
4566+
f'sudo ls {trashed_sv_path}').strip().split('\n')
4567+
return len(trashed_sv_files)
4568+
4569+
def _assert_trashed_sv_has_num_of_files(self, trashed_sv_path,
4570+
num_of_files):
4571+
sv_files = self.mount_a.get_shell_stdout(
4572+
f'sudo ls {trashed_sv_path}').strip().split('\n')
4573+
4574+
self.assertEqual(len(sv_files), num_of_files)
4575+
4576+
def test_pausing_halts_ongoing_purge(self):
4577+
'''
4578+
Test that when MGR config option mgr/volumes/pause_purging is
4579+
set to true, running "ceph fs subvolume rm" will move the subvolume
4580+
to trash but (asynchronous) purge of the subvolume won't happen till
4581+
this config option is not explicitly set to False.
4582+
'''
4583+
v = self.volname
4584+
sv = 'sv1'
4585+
4586+
self.run_ceph_cmd(f'fs subvolume create {v} {sv} --mode=777')
4587+
4588+
sv_path = self._get_sv_path(v, sv)
4589+
# adding more files for this test since in once few runs it fails due
4590+
# to race condition
4591+
self._do_subvolume_io(sv, number_of_files=200)
4592+
4593+
self.run_ceph_cmd(f'fs subvolume rm {v} {sv}')
4594+
# XXX actual test here: test that purging halts
4595+
self.config_set('mgr', self.CONF_OPT, True)
4596+
trashed_sv_path = self._get_trashed_sv_path(sv, sv_path)
4597+
NUM_OF_FILES = self._get_num_of_files_in_trashed_sv(trashed_sv_path)
4598+
time.sleep(2)
4599+
self._assert_trashed_sv_has_num_of_files(trashed_sv_path,
4600+
NUM_OF_FILES)
4601+
4602+
def test_on_resuming_partly_purged_subvol_purges_fully(self):
4603+
'''
4604+
Test that when MGR config option mgr/volumes/pause_purging is
4605+
changed to false, the async purging of a subvolume will resume and
4606+
also finish, causing trash to be empty.
4607+
'''
4608+
v = self.volname
4609+
sv = 'sv1'
4610+
4611+
self.run_ceph_cmd(f'fs subvolume create {v} {sv} --mode=777')
4612+
self._do_subvolume_io(sv, number_of_files=100)
4613+
4614+
self.run_ceph_cmd(f'fs subvolume rm {v} {sv}')
4615+
self.config_set('mgr', self.CONF_OPT, True)
4616+
time.sleep(2)
4617+
4618+
# XXX actual test here: test that purging is resumed and finished
4619+
self.config_set('mgr', self.CONF_OPT, False)
4620+
self._wait_for_trash_empty()
4621+
4622+
44404623
class TestSubvolumeGroupSnapshots(TestVolumesHelper):
44414624
"""Tests for FS subvolume group snapshot operations."""
44424625
@unittest.skip("skipping subvolumegroup snapshot tests")

0 commit comments

Comments
 (0)