<NME> repair_test.py
<BEF> ADDFILE
<MSG> repair_test: add test for repairing read errs and truncations

Signed-off-by: Samuel Just <8c40222f34b9721b5d5709d4ed45337913ea1c3e@inktank.com>

<DFF> @@ -0,0 +1,118 @@
+import logging
+
+import ceph_manager
+from teuthology import misc as teuthology
+
+log = logging.getLogger(__name__)
+
+def setup(ctx, config):
+    ctx.manager.wait_for_clean()
+    ctx.manager.create_pool("repair_test_pool", 1)
+    return "repair_test_pool"
+
+def teardown(ctx, config, pool):
+    ctx.manager.remove_pool(pool)
+    ctx.manager.wait_for_clean()
+
+def run_test(ctx, config, test):
+    s = setup(ctx, config)
+    test(ctx, config, s)
+    teardown(ctx, config, s)
+
+def choose_primary(ctx):
+    def ret(pool, num):
+        log.info("Choosing primary")
+        return ctx.manager.get_pg_primary(pool, num)
+    return ret
+
+def choose_replica(ctx):
+    def ret(pool, num):
+        log.info("Choosing replica")
+        return ctx.manager.get_pg_replica(pool, num)
+    return ret
+
+def trunc(ctx):
+    def ret(osd, pool, obj):
+        log.info("truncating object")
+        return ctx.manager.osd_admin_socket(
+            osd,
+            ['truncobj', pool, obj, '1'])
+    return ret
+
+def dataerr(ctx):
+    def ret(osd, pool, obj):
+        log.info("injecting data err on object")
+        return ctx.manager.osd_admin_socket(
+            osd,
+            ['injectdataerr', pool, obj])
+    return ret
+
+def mdataerr(ctx):
+    def ret(osd, pool, obj):
+        log.info("injecting mdata err on object")
+        return ctx.manager.osd_admin_socket(
+            osd,
+            ['injectmdataerr', pool, obj])
+    return ret
+
+def gen_repair_test(corrupter, chooser, scrub_type):
+    def ret(ctx, config, pool):
+        log.info("starting repair test")
+        victim_osd = chooser(pool, 0)
+
+        # create object
+        log.info("doing put")
+        ctx.manager.do_put(pool, 'repair_test_obj', '/etc/hosts')
+
+        # corrupt object
+        log.info("corrupting object")
+        corrupter(victim_osd, pool, 'repair_test_obj')
+
+        # verify inconsistent
+        log.info("scrubbing")
+        ctx.manager.do_pg_scrub(pool, 0, scrub_type)
+
+        assert ctx.manager.pg_inconsistent(pool, 0)
+
+        # repair
+        log.info("repairing")
+        ctx.manager.do_pg_scrub(pool, 0, "repair")
+
+        log.info("re-scrubbing")
+        ctx.manager.do_pg_scrub(pool, 0, scrub_type)
+
+        # verify consistent
+        assert not ctx.manager.pg_inconsistent(pool, 0)
+        log.info("done")
+    return ret
+
+def task(ctx, config):
+    """
+    Test [deep] repair in several situations:
+      Repair [Truncate, Data EIO, MData EIO] on [Primary|Replica]
+    """
+    if config is None:
+        config = {}
+    assert isinstance(config, dict), \
+        'repair_test task only accepts a dict for config'
+
+    if not hasattr(ctx, 'manager'):
+        first_mon = teuthology.get_first_mon(ctx, config)
+        (mon,) = ctx.cluster.only(first_mon).remotes.iterkeys()
+        ctx.manager = ceph_manager.CephManager(
+            mon,
+            ctx=ctx,
+            logger=log.getChild('ceph_manager')
+            )
+
+    tests = [
+        gen_repair_test(mdataerr(ctx), choose_primary(ctx), "scrub"),
+        gen_repair_test(mdataerr(ctx), choose_replica(ctx), "scrub"),
+        gen_repair_test(dataerr(ctx), choose_primary(ctx), "deep-scrub"),
+        gen_repair_test(dataerr(ctx), choose_replica(ctx), "deep-scrub"),
+        gen_repair_test(trunc(ctx), choose_primary(ctx), "scrub"),
+        gen_repair_test(trunc(ctx), choose_replica(ctx), "scrub")
+        ]
+
+    for test in tests:
+        run_test(ctx, config, test)

{'addition_count': 118, 'commit_subject': 'repair_test: add test for repairing read errs and truncations', 'deletion_count': 0, 'file_extension': '.py', 'lang': 'py', 'license': 'mit', 'repo_name': 'ceph/teuthology'}