]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/cephfs/test_scrub.py
2 Test CephFS scrub (distinct from OSD scrub) functionality
7 from collections
import namedtuple
9 from teuthology
.orchestra
.run
import CommandFailedError
10 from tasks
.cephfs
.cephfs_test_case
import CephFSTestCase
, for_teuthology
12 log
= logging
.getLogger(__name__
)
14 ValidationError
= namedtuple("ValidationError", ["exception", "backtrace"])
17 class Workload(CephFSTestCase
):
18 def __init__(self
, filesystem
, mount
):
20 self
._filesystem
= filesystem
21 self
._initial
_state
= None
23 # Accumulate backtraces for every failed validation, and return them. Backtraces
24 # are rather verbose, but we only see them when something breaks, and they
25 # let us see which check failed without having to decorate each check with
31 Write the workload files to the mount
33 raise NotImplementedError()
37 Read from the mount and validate that the workload files are present (i.e. have
38 survived or been reconstructed from the test scenario)
40 raise NotImplementedError()
44 Damage the filesystem pools in ways that will be interesting to recover from. By
45 default just wipe everything in the metadata pool
47 # Delete every object in the metadata pool
48 objects
= self
._filesystem
.rados(["ls"]).split("\n")
50 self
._filesystem
.rados(["rm", o
])
54 Called after client unmount, after write: flush whatever you want
56 self
._filesystem
.mds_asok(["flush", "journal"])
59 class BacktraceWorkload(Workload
):
61 Single file, single directory, wipe the backtrace and check it.
64 self
._mount
.run_shell(["mkdir", "subdir"])
65 self
._mount
.write_n_mb("subdir/sixmegs", 6)
68 st
= self
._mount
.stat("subdir/sixmegs")
69 self
._filesystem
.mds_asok(["flush", "journal"])
70 bt
= self
._filesystem
.read_backtrace(st
['st_ino'])
71 parent
= bt
['ancestors'][0]['dname']
72 self
.assertEqual(parent
, 'sixmegs')
76 st
= self
._mount
.stat("subdir/sixmegs")
77 self
._filesystem
.mds_asok(["flush", "journal"])
78 self
._filesystem
._write
_data
_xattr
(st
['st_ino'], "parent", "")
81 class DupInodeWorkload(Workload
):
83 Duplicate an inode and try scrubbing it twice."
87 self
._mount
.run_shell(["mkdir", "parent"])
88 self
._mount
.run_shell(["mkdir", "parent/child"])
89 self
._mount
.write_n_mb("parent/parentfile", 6)
90 self
._mount
.write_n_mb("parent/child/childfile", 6)
93 temp_bin_path
= "/tmp/10000000000.00000000_omap.bin"
95 self
._filesystem
.mds_asok(["flush", "journal"])
96 self
._filesystem
.mds_stop()
97 self
._filesystem
.rados(["getomapval", "10000000000.00000000",
98 "parentfile_head", temp_bin_path
])
99 self
._filesystem
.rados(["setomapval", "10000000000.00000000",
100 "shadow_head"], stdin_file
=temp_bin_path
)
101 self
._filesystem
.set_ceph_conf('mds', 'mds hack allow loading invalid metadata', True)
102 self
._filesystem
.mds_restart()
103 self
._filesystem
.wait_for_daemons()
106 out_json
= self
._filesystem
.mds_asok(["scrub_path", "/", "recursive", "repair"])
107 self
.assertNotEqual(out_json
, None)
108 self
.assertTrue(self
._filesystem
.are_daemons_healthy())
112 class TestScrub(CephFSTestCase
):
115 def _scrub(self
, workload
, workers
=1):
117 That when all objects in metadata pool are removed, we can rebuild a metadata pool
118 based on the contents of a data pool, and a client can see and read our files.
121 # First, inject some files
125 # are off by default, but in QA we need to explicitly disable them)
126 self
.fs
.set_ceph_conf('mds', 'mds verify scatter', False)
127 self
.fs
.set_ceph_conf('mds', 'mds debug scatterstat', False)
129 # Apply any data damage the workload wants
132 out_json
= self
.fs
.mds_asok(["scrub_path", "/", "recursive", "repair"])
133 self
.assertNotEqual(out_json
, None)
135 # See that the files are present and correct
136 errors
= workload
.validate()
138 log
.error("Validation errors found: {0}".format(len(errors
)))
140 log
.error(e
.exception
)
141 log
.error(e
.backtrace
)
142 raise AssertionError("Validation failed, first error: {0}\n{1}".format(
143 errors
[0].exception
, errors
[0].backtrace
146 def test_scrub_backtrace(self
):
147 self
._scrub
(BacktraceWorkload(self
.fs
, self
.mount_a
))
149 def test_scrub_dup_inode(self
):
150 self
._scrub
(DupInodeWorkload(self
.fs
, self
.mount_a
))