]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/cephfs/test_volumes.py
eb94251cab9a35836eb09485d9858667bf9be21f
7 from tasks
.cephfs
.cephfs_test_case
import CephFSTestCase
8 from teuthology
.exceptions
import CommandFailedError
10 log
= logging
.getLogger(__name__
)
12 class TestVolumes(CephFSTestCase
):
13 TEST_VOLUME_NAME
= "fs_test_vol"
14 TEST_SUBVOLUME_PREFIX
="subvolume"
15 TEST_GROUP_PREFIX
="group"
16 TEST_SNAPSHOT_PREFIX
="snapshot"
17 TEST_FILE_NAME_PREFIX
="subvolume_file"
19 # for filling subvolume with data
23 DEFAULT_FILE_SIZE
= 1 # MB
24 DEFAULT_NUMBER_OF_FILES
= 1024
26 def _fs_cmd(self
, *args
):
27 return self
.mgr_cluster
.mon_manager
.raw_cluster_cmd("fs", *args
)
29 def _generate_random_subvolume_name(self
):
30 return "{0}_{1}".format(TestVolumes
.TEST_SUBVOLUME_PREFIX
, random
.randint(0, 10000))
32 def _generate_random_group_name(self
):
33 return "{0}_{1}".format(TestVolumes
.TEST_GROUP_PREFIX
, random
.randint(0, 100))
35 def _generate_random_snapshot_name(self
):
36 return "{0}_{1}".format(TestVolumes
.TEST_SNAPSHOT_PREFIX
, random
.randint(0, 100))
38 def _enable_multi_fs(self
):
39 self
._fs
_cmd
("flag", "set", "enable_multiple", "true", "--yes-i-really-mean-it")
41 def _create_or_reuse_test_volume(self
):
42 result
= json
.loads(self
._fs
_cmd
("volume", "ls"))
44 self
.vol_created
= True
45 self
.volname
= TestVolumes
.TEST_VOLUME_NAME
46 self
._fs
_cmd
("volume", "create", self
.volname
)
48 self
.volname
= result
[0]['name']
50 def _get_subvolume_group_path(self
, vol_name
, group_name
):
51 args
= ("subvolumegroup", "getpath", vol_name
, group_name
)
52 path
= self
._fs
_cmd
(*args
)
53 # remove the leading '/', and trailing whitespaces
54 return path
[1:].rstrip()
56 def _get_subvolume_path(self
, vol_name
, subvol_name
, group_name
=None):
57 args
= ["subvolume", "getpath", vol_name
, subvol_name
]
59 args
.append(group_name
)
61 path
= self
._fs
_cmd
(*args
)
62 # remove the leading '/', and trailing whitespaces
63 return path
[1:].rstrip()
65 def _delete_test_volume(self
):
66 self
._fs
_cmd
("volume", "rm", self
.volname
)
68 def _do_subvolume_io(self
, subvolume
, number_of_files
=DEFAULT_NUMBER_OF_FILES
,
69 file_size
=DEFAULT_FILE_SIZE
):
70 # get subvolume path for IO
71 subvolpath
= self
._fs
_cmd
("subvolume", "getpath", self
.volname
, subvolume
)
72 self
.assertNotEqual(subvolpath
, None)
73 subvolpath
= subvolpath
[1:].rstrip() # remove "/" prefix and any trailing newline
75 log
.debug("filling subvolume {0} with {1} files each {2}MB size".format(subvolume
, number_of_files
, file_size
))
76 for i
in range(number_of_files
):
77 filename
= "{0}.{1}".format(TestVolumes
.TEST_FILE_NAME_PREFIX
, i
)
78 self
.mount_a
.write_n_mb(os
.path
.join(subvolpath
, filename
), file_size
)
80 def _wait_for_trash_empty(self
, timeout
=30):
81 # XXX: construct the trash dir path (note that there is no mgr
82 # [sub]volume interface for this).
83 trashdir
= os
.path
.join("./", "volumes", "_deleting")
84 self
.mount_a
.wait_for_dir_empty(trashdir
)
87 super(TestVolumes
, self
).setUp()
89 self
.vol_created
= False
90 self
._enable
_multi
_fs
()
91 self
._create
_or
_reuse
_test
_volume
()
95 self
._delete
_test
_volume
()
96 super(TestVolumes
, self
).tearDown()
98 ### basic subvolume operations
100 def test_subvolume_create_and_rm(self
):
102 subvolume
= self
._generate
_random
_subvolume
_name
()
103 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
105 # make sure it exists
106 subvolpath
= self
._fs
_cmd
("subvolume", "getpath", self
.volname
, subvolume
)
107 self
.assertNotEqual(subvolpath
, None)
110 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
113 self
._fs
_cmd
("subvolume", "getpath", self
.volname
, subvolume
)
114 except CommandFailedError
as ce
:
115 if ce
.exitstatus
!= errno
.ENOENT
:
118 # verify trash dir is clean
119 self
._wait
_for
_trash
_empty
()
121 def test_subvolume_create_idempotence(self
):
123 subvolume
= self
._generate
_random
_subvolume
_name
()
124 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
126 # try creating w/ same subvolume name -- should be idempotent
127 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
130 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
132 # verify trash dir is clean
133 self
._wait
_for
_trash
_empty
()
135 def test_nonexistent_subvolume_rm(self
):
136 # remove non-existing subvolume
137 subvolume
= "non_existent_subvolume"
139 # try, remove subvolume
141 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
142 except CommandFailedError
as ce
:
143 if ce
.exitstatus
!= errno
.ENOENT
:
146 # force remove subvolume
147 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, "--force")
149 def test_nonexistent_subvolume_group_create(self
):
150 subvolume
= self
._generate
_random
_subvolume
_name
()
151 group
= "non_existent_group"
153 # try, creating subvolume in a nonexistent group
155 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
156 except CommandFailedError
as ce
:
157 if ce
.exitstatus
!= errno
.ENOENT
:
160 def test_default_uid_gid_subvolume(self
):
161 subvolume
= self
._generate
_random
_subvolume
_name
()
166 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
167 subvol_path
= self
._get
_subvolume
_path
(self
.volname
, subvolume
)
169 # check subvolume's uid and gid
170 stat
= self
.mount_a
.stat(subvol_path
)
171 self
.assertEqual(stat
['st_uid'], expected_uid
)
172 self
.assertEqual(stat
['st_gid'], expected_gid
)
175 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
177 ### subvolume group operations
179 def test_subvolume_create_and_rm_in_group(self
):
180 subvolume
= self
._generate
_random
_subvolume
_name
()
181 group
= self
._generate
_random
_group
_name
()
184 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
186 # create subvolume in group
187 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
190 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, group
)
192 # verify trash dir is clean
193 self
._wait
_for
_trash
_empty
()
196 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
198 def test_subvolume_group_create_with_desired_data_pool_layout(self
):
199 group1
= self
._generate
_random
_group
_name
()
200 group2
= self
._generate
_random
_group
_name
()
203 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group1
)
204 group1_path
= self
._get
_subvolume
_group
_path
(self
.volname
, group1
)
206 default_pool
= self
.mount_a
.getfattr(group1_path
, "ceph.dir.layout.pool")
207 new_pool
= "new_pool"
208 self
.assertNotEqual(default_pool
, new_pool
)
211 self
.fs
.add_data_pool(new_pool
)
213 # create group specifying the new data pool as its pool layout
214 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group2
,
215 "--pool_layout", new_pool
)
216 group2_path
= self
._get
_subvolume
_group
_path
(self
.volname
, group2
)
218 desired_pool
= self
.mount_a
.getfattr(group2_path
, "ceph.dir.layout.pool")
219 self
.assertEqual(desired_pool
, new_pool
)
221 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group1
)
222 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group2
)
224 def test_subvolume_create_with_desired_data_pool_layout_in_group(self
):
225 subvol1
= self
._generate
_random
_subvolume
_name
()
226 subvol2
= self
._generate
_random
_subvolume
_name
()
227 group
= self
._generate
_random
_group
_name
()
229 # create group. this also helps set default pool layout for subvolumes
230 # created within the group.
231 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
233 # create subvolume in group.
234 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvol1
, "--group_name", group
)
235 subvol1_path
= self
._get
_subvolume
_path
(self
.volname
, subvol1
, group_name
=group
)
237 default_pool
= self
.mount_a
.getfattr(subvol1_path
, "ceph.dir.layout.pool")
238 new_pool
= "new_pool"
239 self
.assertNotEqual(default_pool
, new_pool
)
242 self
.fs
.add_data_pool(new_pool
)
244 # create subvolume specifying the new data pool as its pool layout
245 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvol2
, "--group_name", group
,
246 "--pool_layout", new_pool
)
247 subvol2_path
= self
._get
_subvolume
_path
(self
.volname
, subvol2
, group_name
=group
)
249 desired_pool
= self
.mount_a
.getfattr(subvol2_path
, "ceph.dir.layout.pool")
250 self
.assertEqual(desired_pool
, new_pool
)
252 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvol2
, group
)
253 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvol1
, group
)
254 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
256 def test_subvolume_group_create_with_desired_mode(self
):
257 group1
= self
._generate
_random
_group
_name
()
258 group2
= self
._generate
_random
_group
_name
()
260 expected_mode1
= "755"
262 expected_mode2
= "777"
265 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group1
)
266 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group2
, "--mode", "777")
268 group1_path
= self
._get
_subvolume
_group
_path
(self
.volname
, group1
)
269 group2_path
= self
._get
_subvolume
_group
_path
(self
.volname
, group2
)
272 actual_mode1
= self
.mount_a
.run_shell(['stat', '-c' '%a', group1_path
]).stdout
.getvalue().strip()
273 actual_mode2
= self
.mount_a
.run_shell(['stat', '-c' '%a', group2_path
]).stdout
.getvalue().strip()
274 self
.assertEqual(actual_mode1
, expected_mode1
)
275 self
.assertEqual(actual_mode2
, expected_mode2
)
277 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group1
)
278 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group2
)
280 def test_subvolume_create_with_desired_mode_in_group(self
):
281 subvol1
= self
._generate
_random
_subvolume
_name
()
282 subvol2
= self
._generate
_random
_subvolume
_name
()
283 subvol3
= self
._generate
_random
_subvolume
_name
()
284 group
= self
._generate
_random
_group
_name
()
286 expected_mode1
= "755"
288 expected_mode2
= "777"
291 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
293 # create subvolume in group
294 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvol1
, "--group_name", group
)
295 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvol2
, "--group_name", group
, "--mode", "777")
296 # check whether mode 0777 also works
297 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvol3
, "--group_name", group
, "--mode", "0777")
299 subvol1_path
= self
._get
_subvolume
_path
(self
.volname
, subvol1
, group_name
=group
)
300 subvol2_path
= self
._get
_subvolume
_path
(self
.volname
, subvol2
, group_name
=group
)
301 subvol3_path
= self
._get
_subvolume
_path
(self
.volname
, subvol3
, group_name
=group
)
303 # check subvolume's mode
304 actual_mode1
= self
.mount_a
.run_shell(['stat', '-c' '%a', subvol1_path
]).stdout
.getvalue().strip()
305 actual_mode2
= self
.mount_a
.run_shell(['stat', '-c' '%a', subvol2_path
]).stdout
.getvalue().strip()
306 actual_mode3
= self
.mount_a
.run_shell(['stat', '-c' '%a', subvol3_path
]).stdout
.getvalue().strip()
307 self
.assertEqual(actual_mode1
, expected_mode1
)
308 self
.assertEqual(actual_mode2
, expected_mode2
)
309 self
.assertEqual(actual_mode3
, expected_mode2
)
311 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvol1
, group
)
312 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvol2
, group
)
313 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvol3
, group
)
314 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
316 def test_nonexistent_subvolme_group_rm(self
):
317 group
= "non_existent_group"
319 # try, remove subvolume group
321 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
322 except CommandFailedError
as ce
:
323 if ce
.exitstatus
!= errno
.ENOENT
:
326 # force remove subvolume
327 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
, "--force")
329 def test_default_uid_gid_subvolume_group(self
):
330 group
= self
._generate
_random
_group
_name
()
335 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
336 group_path
= self
._get
_subvolume
_group
_path
(self
.volname
, group
)
338 # check group's uid and gid
339 stat
= self
.mount_a
.stat(group_path
)
340 self
.assertEqual(stat
['st_uid'], expected_uid
)
341 self
.assertEqual(stat
['st_gid'], expected_gid
)
344 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
346 ### snapshot operations
348 def test_subvolume_snapshot_create_and_rm(self
):
349 subvolume
= self
._generate
_random
_subvolume
_name
()
350 snapshot
= self
._generate
_random
_snapshot
_name
()
353 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
356 self
._fs
_cmd
("subvolume", "snapshot", "create", self
.volname
, subvolume
, snapshot
)
359 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
)
362 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
364 # verify trash dir is clean
365 self
._wait
_for
_trash
_empty
()
367 def test_subvolume_snapshot_create_idempotence(self
):
368 subvolume
= self
._generate
_random
_subvolume
_name
()
369 snapshot
= self
._generate
_random
_snapshot
_name
()
372 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
375 self
._fs
_cmd
("subvolume", "snapshot", "create", self
.volname
, subvolume
, snapshot
)
377 # try creating w/ same subvolume snapshot name -- should be idempotent
378 self
._fs
_cmd
("subvolume", "snapshot", "create", self
.volname
, subvolume
, snapshot
)
381 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
)
384 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
386 # verify trash dir is clean
387 self
._wait
_for
_trash
_empty
()
389 def test_nonexistent_subvolume_snapshot_rm(self
):
390 subvolume
= self
._generate
_random
_subvolume
_name
()
391 snapshot
= self
._generate
_random
_snapshot
_name
()
394 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
397 self
._fs
_cmd
("subvolume", "snapshot", "create", self
.volname
, subvolume
, snapshot
)
400 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
)
402 # remove snapshot again
404 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
)
405 except CommandFailedError
as ce
:
406 if ce
.exitstatus
!= errno
.ENOENT
:
409 # force remove snapshot
410 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
, "--force")
413 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
415 # verify trash dir is clean
416 self
._wait
_for
_trash
_empty
()
418 def test_subvolume_snapshot_in_group(self
):
419 subvolume
= self
._generate
_random
_subvolume
_name
()
420 group
= self
._generate
_random
_group
_name
()
421 snapshot
= self
._generate
_random
_snapshot
_name
()
424 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
426 # create subvolume in group
427 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
429 # snapshot subvolume in group
430 self
._fs
_cmd
("subvolume", "snapshot", "create", self
.volname
, subvolume
, snapshot
, group
)
433 self
._fs
_cmd
("subvolume", "snapshot", "rm", self
.volname
, subvolume
, snapshot
, group
)
436 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, group
)
438 # verify trash dir is clean
439 self
._wait
_for
_trash
_empty
()
442 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
444 def test_subvolume_group_snapshot_create_and_rm(self
):
445 subvolume
= self
._generate
_random
_subvolume
_name
()
446 group
= self
._generate
_random
_group
_name
()
447 snapshot
= self
._generate
_random
_snapshot
_name
()
450 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
452 # create subvolume in group
453 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
456 self
._fs
_cmd
("subvolumegroup", "snapshot", "create", self
.volname
, group
, snapshot
)
459 self
._fs
_cmd
("subvolumegroup", "snapshot", "rm", self
.volname
, group
, snapshot
)
462 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, group
)
464 # verify trash dir is clean
465 self
._wait
_for
_trash
_empty
()
468 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
470 def test_subvolume_group_snapshot_idempotence(self
):
471 subvolume
= self
._generate
_random
_subvolume
_name
()
472 group
= self
._generate
_random
_group
_name
()
473 snapshot
= self
._generate
_random
_snapshot
_name
()
476 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
478 # create subvolume in group
479 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
482 self
._fs
_cmd
("subvolumegroup", "snapshot", "create", self
.volname
, group
, snapshot
)
484 # try creating snapshot w/ same snapshot name -- shoule be idempotent
485 self
._fs
_cmd
("subvolumegroup", "snapshot", "create", self
.volname
, group
, snapshot
)
488 self
._fs
_cmd
("subvolumegroup", "snapshot", "rm", self
.volname
, group
, snapshot
)
491 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, group
)
493 # verify trash dir is clean
494 self
._wait
_for
_trash
_empty
()
497 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
499 def test_nonexistent_subvolume_group_snapshot_rm(self
):
500 subvolume
= self
._generate
_random
_subvolume
_name
()
501 group
= self
._generate
_random
_group
_name
()
502 snapshot
= self
._generate
_random
_snapshot
_name
()
505 self
._fs
_cmd
("subvolumegroup", "create", self
.volname
, group
)
507 # create subvolume in group
508 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
, "--group_name", group
)
511 self
._fs
_cmd
("subvolumegroup", "snapshot", "create", self
.volname
, group
, snapshot
)
514 self
._fs
_cmd
("subvolumegroup", "snapshot", "rm", self
.volname
, group
, snapshot
)
518 self
._fs
_cmd
("subvolumegroup", "snapshot", "rm", self
.volname
, group
, snapshot
)
519 except CommandFailedError
as ce
:
520 if ce
.exitstatus
!= errno
.ENOENT
:
524 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
, group
)
526 # verify trash dir is clean
527 self
._wait
_for
_trash
_empty
()
530 self
._fs
_cmd
("subvolumegroup", "rm", self
.volname
, group
)
532 def test_async_subvolume_rm(self
):
533 subvolume
= self
._generate
_random
_subvolume
_name
()
536 self
._fs
_cmd
("subvolume", "create", self
.volname
, subvolume
)
538 # fill subvolume w/ some data
539 self
._do
_subvolume
_io
(subvolume
)
541 self
.mount_a
.umount_wait()
544 self
._fs
_cmd
("subvolume", "rm", self
.volname
, subvolume
)
548 # verify trash dir is clean
549 self
._wait
_for
_trash
_empty
()