Skip to content

Commit 008dbe9

Browse files
qa/cephfs: improve caps_helper.CapTester
Improvement #1: CapTester.write_test_files() not only creates the test file but also does the following for every mount object it receives in parameters - * carefully produces the path for the test file as per parameters received * generates the unique data for each test file on a CephFS mount * creates a data structure -- list of lists -- that holds all this information along with mount object itself for each mount object so that tests can be conducted at a later point Untangle this mess of code by splitting this method into 3 separate methods - 1. To produce the path for test file (as per user's need). 2. To generate the data that will be written into the test file. 3. To actually create the test file on CephFS. Improvement #2: Remove the internal data structure used for testing -- self.test_set -- and use separate class attributes to store all the data required for testing instead of a tuple. This serves two purpose - One, it makes it easy to manipulate all this data from helper methods and during debugging session, especially while using a PDB session. And two, make it impossible to have multiple mounts/multiple "test sets" within same CapTester instance for the sake of simplicity. Users can instead create two instances of CapTester instances if needed. Signed-off-by: Rishabh Dave <ridave@redhat.com>
1 parent e8bdf94 commit 008dbe9

File tree

3 files changed

+125
-117
lines changed

3 files changed

+125
-117
lines changed

qa/tasks/cephfs/caps_helper.py

Lines changed: 72 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ class CapTester:
119119
run_mon_cap_tests() or run_mds_cap_tests() as per the need.
120120
"""
121121

122-
def write_test_files(self, mounts, testpath=''):
122+
def __init__(self, mount=None, path=''):
123+
self._create_test_files(mount, path)
124+
125+
def _create_test_files(self, mount, path):
123126
"""
124127
Exercising 'r' and 'w' access levels on a file on CephFS mount is
125128
pretty routine across all tests for caps. Adding to method to write
@@ -129,39 +132,47 @@ def write_test_files(self, mounts, testpath=''):
129132
at the path passed in testpath for the given list of mounts. If
130133
testpath is empty, the file is created at the root of the CephFS.
131134
"""
132-
dirname, filename = 'testdir', 'testfile'
133-
self.test_set = []
134-
# XXX: The reason behind testpath[1:] below is that the testpath is
135+
# CephFS mount where read/write test will be conducted.
136+
self.mount = mount
137+
# Path where out test file located.
138+
self.path = self._gen_test_file_path(path)
139+
# Data that out test file will contain.
140+
self.data = self._gen_test_file_data()
141+
142+
self.mount.write_file(self.path, self.data)
143+
log.info(f'Test file has been created on FS '
144+
f'"{self.mount.cephfs_name}" at path "{self.path}" with the '
145+
f'following data -\n{self.data}')
146+
147+
def _gen_test_file_path(self, path=''):
148+
# XXX: The reason behind path[1:] below is that the path is
135149
# supposed to contain a path inside CephFS (which might be passed as
136150
# an absolute path). os.path.join() deletes all previous path
137151
# components when it encounters a path component starting with '/'.
138-
# Deleting the first '/' from the string in testpath ensures that
152+
# Deleting the first '/' from the string in path ensures that
139153
# previous path components are not deleted by os.path.join().
140-
if testpath:
141-
testpath = testpath[1:] if testpath[0] == '/' else testpath
142-
# XXX: passing just '/' screw up os.path.join() ahead.
143-
if testpath == '/':
144-
testpath = ''
145-
146-
for mount_x in mounts:
147-
log.info(f'creating test file on FS {mount_x.cephfs_name} '
148-
f'mounted at {mount_x.mountpoint}...')
149-
dirpath = os_path_join(mount_x.hostfs_mntpt, testpath, dirname)
150-
mount_x.run_shell(f'mkdir {dirpath}')
151-
filepath = os_path_join(dirpath, filename)
152-
# XXX: the reason behind adding filepathm, cephfs_name and both
153-
# mntpts is to avoid a test bug where we mount cephfs1 but what
154-
# ends up being mounted cephfs2. since filepath and filedata are
155-
# identical, how would tests figure otherwise that they are
156-
# accessing the right filename but on wrong CephFS.
157-
filedata = (f'filepath = {filepath}\n'
158-
f'cephfs_name = {mount_x.cephfs_name}\n'
159-
f'cephfs_mntpt = {mount_x.cephfs_mntpt}\n'
160-
f'hostfs_mntpt = {mount_x.hostfs_mntpt}')
161-
mount_x.write_file(filepath, filedata)
162-
self.test_set.append([mount_x, filepath, filedata])
163-
log.info(f'Test file created at "{filepath}" with the following '
164-
f'data -\n"{filedata}"')
154+
if path:
155+
path = path[1:] if path[0] == '/' else path
156+
# XXX: passing just '/' messes up os.path.join() ahead.
157+
if path == '/':
158+
path = ''
159+
160+
dirname, filename = 'testdir', 'testfile'
161+
dirpath = os_path_join(self.mount.hostfs_mntpt, path, dirname)
162+
self.mount.run_shell(f'mkdir {dirpath}')
163+
return os_path_join(dirpath, filename)
164+
165+
def _gen_test_file_data(self):
166+
# XXX: the reason behind adding path, cephfs_name and both
167+
# mntpts is to avoid a test bug where we mount cephfs1 but what
168+
# ends up being mounted cephfs2. since self.path and self.data are
169+
# identical, how would tests figure otherwise that they are
170+
# accessing the right filename but on wrong CephFS.
171+
return dedent(f'''\
172+
self.path = {self.path}
173+
cephfs_name = {self.mount.cephfs_name}
174+
cephfs_mntpt = {self.mount.cephfs_mntpt}
175+
hostfs_mntpt = {self.mount.hostfs_mntpt}''')
165176

166177
def run_cap_tests(self, perm, mntpt=None):
167178
# TODO
@@ -235,15 +246,17 @@ def run_mds_cap_tests(self, perm, mntpt=None):
235246
Run test for read perm and, for write perm, run positive test if it
236247
is present and run negative test if not.
237248
"""
238-
# XXX: mntpt is path inside cephfs that serves as root for current
239-
# mount. Therefore, this path must me deleted from self.filepaths.
240-
# Example -
241-
# orignal path: /mnt/cephfs_x/dir1/dir2/testdir
242-
# cephfs dir serving as root for current mnt: /dir1/dir2
243-
# therefore, final path: /mnt/cephfs_x/testdir
244249
if mntpt:
245-
self.test_set = [(x, y.replace(mntpt, ''), z) for x, y, z in \
246-
self.test_set]
250+
# beacaue we want to value of mntpt from test_set.path along with
251+
# slash that precedes it.
252+
mntpt = '/' + mntpt if mntpt[0] != '/' else mntpt
253+
# XXX: mntpt is path inside cephfs that serves as root for current
254+
# mount. Therefore, this path must me deleted from self.path.
255+
# Example -
256+
# orignal path: /mnt/cephfs_x/dir1/dir2/testdir
257+
# cephfs dir serving as root for current mnt: /dir1/dir2
258+
# therefore, final path: /mnt/cephfs_x/testdir
259+
self.path = self.path.replace(mntpt, '')
247260

248261
self.conduct_pos_test_for_read_caps()
249262

@@ -255,35 +268,33 @@ def run_mds_cap_tests(self, perm, mntpt=None):
255268
raise RuntimeError(f'perm = {perm}\nIt should be "r" or "rw".')
256269

257270
def conduct_pos_test_for_read_caps(self):
258-
for mount, path, data in self.test_set:
259-
log.info(f'test read perm: read file {path} and expect data '
260-
f'"{data}"')
261-
contents = mount.read_file(path)
262-
assert_equal(data, contents)
263-
log.info(f'read perm was tested successfully: "{data}" was '
264-
f'successfully read from path {path}')
271+
log.info(f'test read perm: read file {self.path} and expect data '
272+
f'"{self.data}"')
273+
contents = self.mount.read_file(self.path)
274+
assert_equal(self.data, contents)
275+
log.info(f'read perm was tested successfully: "{self.data}" was '
276+
f'successfully read from path {self.path}')
265277

266278
def conduct_pos_test_for_write_caps(self):
267-
for mount, path, data in self.test_set:
268-
log.info(f'test write perm: try writing data "{data}" to '
269-
f'file {path}.')
270-
mount.write_file(path=path, data=data)
271-
contents = mount.read_file(path=path)
272-
assert_equal(data, contents)
273-
log.info(f'write perm was tested was successfully: data '
274-
f'"{data}" was successfully written to file "{path}".')
279+
log.info(f'test write perm: try writing data "{self.data}" to '
280+
f'file {self.path}.')
281+
self.mount.write_file(path=self.path, data=self.data)
282+
contents = self.mount.read_file(path=self.path)
283+
assert_equal(self.data, contents)
284+
log.info(f'write perm was tested was successfully: self.data '
285+
f'"{self.data}" was successfully written to file '
286+
f'"{self.path}".')
275287

276288
def conduct_neg_test_for_write_caps(self, sudo_write=False):
277289
possible_errmsgs = ('permission denied', 'operation not permitted')
278290
cmdargs = ['echo', 'some random data', Raw('|')]
279291
cmdargs += ['sudo', 'tee'] if sudo_write else ['tee']
280292

281293
# don't use data, cmd args to write are set already above.
282-
for mount, path, data in self.test_set:
283-
log.info('test absence of write perm: expect failure '
284-
f'writing data to file {path}.')
285-
cmdargs.append(path)
286-
mount.negtestcmd(args=cmdargs, retval=1, errmsgs=possible_errmsgs)
287-
cmdargs.pop(-1)
288-
log.info('absence of write perm was tested successfully: '
289-
f'failed to be write data to file {path}.')
294+
log.info('test absence of write perm: expect failure '
295+
f'writing data to file {self.path}.')
296+
cmdargs.append(self.path)
297+
self.mount.negtestcmd(args=cmdargs, retval=1, errmsgs=possible_errmsgs)
298+
cmdargs.pop(-1)
299+
log.info('absence of write perm was tested successfully: '
300+
f'failed to be write data to file {self.path}.')

qa/tasks/cephfs/test_admin.py

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,27 +1206,30 @@ class TestFsAuthorize(CephFSTestCase):
12061206
def test_single_path_r(self):
12071207
PERM = 'r'
12081208
FS_AUTH_CAPS = (('/', PERM),)
1209-
self.captester = CapTester()
1210-
self.setup_test_env(FS_AUTH_CAPS)
1209+
self.captester = CapTester(self.mount_a, '/')
1210+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
12111211

1212+
self._remount(keyring)
12121213
self.captester.run_mon_cap_tests(self.fs, self.client_id)
12131214
self.captester.run_mds_cap_tests(PERM)
12141215

12151216
def test_single_path_rw(self):
12161217
PERM = 'rw'
12171218
FS_AUTH_CAPS = (('/', PERM),)
1218-
self.captester = CapTester()
1219-
self.setup_test_env(FS_AUTH_CAPS)
1219+
self.captester = CapTester(self.mount_a, '/')
1220+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
12201221

1222+
self._remount(keyring)
12211223
self.captester.run_mon_cap_tests(self.fs, self.client_id)
12221224
self.captester.run_mds_cap_tests(PERM)
12231225

12241226
def test_single_path_rootsquash(self):
12251227
PERM = 'rw'
12261228
FS_AUTH_CAPS = (('/', PERM, 'root_squash'),)
1227-
self.captester = CapTester()
1228-
self.setup_test_env(FS_AUTH_CAPS)
1229+
self.captester = CapTester(self.mount_a, '/')
1230+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
12291231

1232+
self._remount(keyring)
12301233
# testing MDS caps...
12311234
# Since root_squash is set in client caps, client can read but not
12321235
# write even thought access level is set to "rw".
@@ -1250,32 +1253,35 @@ def test_single_path_authorize_on_nonalphanumeric_fsname(self):
12501253
self.mount_a.remount(cephfs_name=self.fs.name)
12511254
PERM = 'rw'
12521255
FS_AUTH_CAPS = (('/', PERM),)
1253-
self.captester = CapTester()
1254-
self.setup_test_env(FS_AUTH_CAPS)
1256+
self.captester = CapTester(self.mount_a, '/')
1257+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
1258+
1259+
self._remount(keyring)
12551260
self.captester.run_mds_cap_tests(PERM)
12561261

12571262
def test_multiple_path_r(self):
12581263
PERM = 'r'
12591264
FS_AUTH_CAPS = (('/dir1/dir12', PERM), ('/dir2/dir22', PERM))
12601265
for c in FS_AUTH_CAPS:
12611266
self.mount_a.run_shell(f'mkdir -p .{c[0]}')
1262-
self.captesters = (CapTester(), CapTester())
1263-
self.setup_test_env(FS_AUTH_CAPS)
1267+
self.captesters = (CapTester(self.mount_a, '/dir1/dir12'),
1268+
CapTester(self.mount_a, '/dir2/dir22'))
1269+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
12641270

1265-
self.run_cap_test_one_by_one(FS_AUTH_CAPS)
1271+
self._remount_and_run_tests(FS_AUTH_CAPS, keyring)
12661272

12671273
def test_multiple_path_rw(self):
12681274
PERM = 'rw'
12691275
FS_AUTH_CAPS = (('/dir1/dir12', PERM), ('/dir2/dir22', PERM))
12701276
for c in FS_AUTH_CAPS:
12711277
self.mount_a.run_shell(f'mkdir -p .{c[0]}')
1272-
self.captesters = (CapTester(), CapTester())
1273-
self.setup_test_env(FS_AUTH_CAPS)
1278+
self.captesters = (CapTester(self.mount_a, '/dir1/dir12'),
1279+
CapTester(self.mount_a, '/dir2/dir22'))
1280+
keyring = self.fs.authorize(self.client_id, FS_AUTH_CAPS)
12741281

1275-
self.run_cap_test_one_by_one(FS_AUTH_CAPS)
1282+
self._remount_and_run_tests(FS_AUTH_CAPS, keyring)
12761283

1277-
def run_cap_test_one_by_one(self, fs_auth_caps):
1278-
keyring = self.run_cluster_cmd(f'auth get {self.client_name}')
1284+
def _remount_and_run_tests(self, fs_auth_caps, keyring):
12791285
for i, c in enumerate(fs_auth_caps):
12801286
self.assertIn(i, (0, 1))
12811287
PATH = c[0]
@@ -1297,24 +1303,6 @@ def _remount(self, keyring, path='/'):
12971303
client_keyring_path=keyring_path,
12981304
cephfs_mntpt=path)
12991305

1300-
def setup_for_single_path(self, fs_auth_caps):
1301-
self.captester.write_test_files((self.mount_a,), '/')
1302-
keyring = self.fs.authorize(self.client_id, fs_auth_caps)
1303-
self._remount(keyring)
1304-
1305-
def setup_for_multiple_paths(self, fs_auth_caps):
1306-
for i, c in enumerate(fs_auth_caps):
1307-
PATH = c[0]
1308-
self.captesters[i].write_test_files((self.mount_a,), PATH)
1309-
1310-
self.fs.authorize(self.client_id, fs_auth_caps)
1311-
1312-
def setup_test_env(self, fs_auth_caps):
1313-
if len(fs_auth_caps) == 1:
1314-
self.setup_for_single_path(fs_auth_caps[0])
1315-
else:
1316-
self.setup_for_multiple_paths(fs_auth_caps)
1317-
13181306

13191307
class TestAdminCommandIdempotency(CephFSTestCase):
13201308
"""

0 commit comments

Comments
 (0)