]>
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(object):
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
29 def assert_equal(self
, a
, b
):
32 raise AssertionError("{0} != {1}".format(a
, b
))
33 except AssertionError as e
:
35 ValidationError(e
, traceback
.format_exc(3))
40 Write the workload files to the mount
42 raise NotImplementedError()
46 Read from the mount and validate that the workload files are present (i.e. have
47 survived or been reconstructed from the test scenario)
49 raise NotImplementedError()
53 Damage the filesystem pools in ways that will be interesting to recover from. By
54 default just wipe everything in the metadata pool
56 # Delete every object in the metadata pool
57 objects
= self
._filesystem
.rados(["ls"]).split("\n")
59 self
._filesystem
.rados(["rm", o
])
63 Called after client unmount, after write: flush whatever you want
65 self
._filesystem
.mds_asok(["flush", "journal"])
68 class BacktraceWorkload(Workload
):
70 Single file, single directory, wipe the backtrace and check it.
73 self
._mount
.run_shell(["mkdir", "subdir"])
74 self
._mount
.write_n_mb("subdir/sixmegs", 6)
77 st
= self
._mount
.stat("subdir/sixmegs")
78 self
._filesystem
.mds_asok(["flush", "journal"])
79 bt
= self
._filesystem
.read_backtrace(st
['st_ino'])
80 parent
= bt
['ancestors'][0]['dname']
81 self
.assert_equal(parent
, "sixmegs")
85 st
= self
._mount
.stat("subdir/sixmegs")
86 self
._filesystem
.mds_asok(["flush", "journal"])
87 self
._filesystem
._write
_data
_xattr
(st
['st_ino'], "parent", "")
90 class DupInodeWorkload(Workload
):
92 Duplicate an inode and try scrubbing it twice."
96 self
._mount
.run_shell(["mkdir", "parent"])
97 self
._mount
.run_shell(["mkdir", "parent/child"])
98 self
._mount
.write_n_mb("parent/parentfile", 6)
99 self
._mount
.write_n_mb("parent/child/childfile", 6)
102 temp_bin_path
= "/tmp/10000000000.00000000_omap.bin"
104 self
._filesystem
.mds_asok(["flush", "journal"])
105 self
._filesystem
.mds_stop()
106 self
._filesystem
.rados(["getomapval", "10000000000.00000000",
107 "parentfile_head", temp_bin_path
])
108 self
._filesystem
.rados(["setomapval", "10000000000.00000000",
109 "shadow_head"], stdin_file
=temp_bin_path
)
110 self
._filesystem
.set_ceph_conf('mds', 'mds hack allow loading invalid metadata', True)
111 self
._filesystem
.mds_restart()
112 self
._filesystem
.wait_for_daemons()
115 self
._filesystem
.mds_asok(["scrub_path", "/", "recursive", "repair"])
116 self
.assert_equal(self
._filesystem
.are_daemons_healthy(), True)
120 class TestScrub(CephFSTestCase
):
123 def _scrub(self
, workload
, workers
=1):
125 That when all objects in metadata pool are removed, we can rebuild a metadata pool
126 based on the contents of a data pool, and a client can see and read our files.
129 # First, inject some files
133 # are off by default, but in QA we need to explicitly disable them)
134 self
.fs
.set_ceph_conf('mds', 'mds verify scatter', False)
135 self
.fs
.set_ceph_conf('mds', 'mds debug scatterstat', False)
137 # Apply any data damage the workload wants
140 self
.fs
.mds_asok(["scrub_path", "/", "recursive", "repair"])
142 # See that the files are present and correct
143 errors
= workload
.validate()
145 log
.error("Validation errors found: {0}".format(len(errors
)))
147 log
.error(e
.exception
)
148 log
.error(e
.backtrace
)
149 raise AssertionError("Validation failed, first error: {0}\n{1}".format(
150 errors
[0].exception
, errors
[0].backtrace
153 def test_scrub_backtrace(self
):
154 self
._scrub
(BacktraceWorkload(self
.fs
, self
.mount_a
))
156 def test_scrub_dup_inode(self
):
157 self
._scrub
(DupInodeWorkload(self
.fs
, self
.mount_a
))