]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
tasks/scrub_test: add test for get-inconsistent-* commands
authorKefu Chai <kchai@redhat.com>
Tue, 16 Feb 2016 10:40:27 +0000 (18:40 +0800)
committerKefu Chai <kchai@redhat.com>
Mon, 22 Feb 2016 10:35:50 +0000 (18:35 +0800)
Signed-off-by: Kefu Chai <kchai@redhat.com>
suites/rados/basic/tasks/scrub_test.yaml
tasks/scrub_test.py

index 2b87c3f0dffa621588fbd07aaea1285ed751bdc4..e3b07b6f7fd1fc21d34de227a35b7de8bc4d5914 100644 (file)
@@ -11,6 +11,8 @@ overrides:
     - deep-scrub 1 errors
     - repair 0 missing, 1 inconsistent objects
     - repair 1 errors, 1 fixed
+    - shard [0-9]+ missing
+    - deep-scrub 1 missing, 0 inconsistent objects
 tasks:
 - install:
 - ceph:
index 2b2caf6d7aae63a0b51c8a93880ff89270352c43..34359a4665b7a798df83fd15ed4f92c347bb006b 100644 (file)
@@ -2,9 +2,12 @@
 from cStringIO import StringIO
 
 import contextlib
+import json
 import logging
 import os
 import time
+import ctypes
+import tempfile
 
 import ceph_manager
 from teuthology import misc as teuthology
@@ -137,6 +140,181 @@ def test_repair_bad_omap(ctx, manager, pg, osd, objname):
     repair(manager, pg)
 
 
+class MessUp:
+    def __init__(self, manager, osd_remote, pool, osd_id,
+                 obj_name, obj_path, omap_key, omap_val):
+        self.manager = manager
+        self.osd = osd_remote
+        self.pool = pool
+        self.osd_id = osd_id
+        self.obj = obj_name
+        self.path = obj_path
+        self.omap_key = omap_key
+        self.omap_val = omap_val
+
+    @contextlib.contextmanager
+    def _test_with_file(self, messup_cmd, *checks):
+        temp = tempfile.mktemp()
+        backup_cmd = ['sudo', 'cp', self.path, temp]
+        self.osd.run(args=backup_cmd)
+        self.osd.run(args=messup_cmd.split())
+        yield checks
+        restore_cmd = ['sudo', 'mv', temp, self.path]
+        self.osd.run(args=restore_cmd)
+
+    def remove(self):
+        cmd = 'sudo rm {path}'.format(path=self.path)
+        return self._test_with_file(cmd, 'missing')
+
+    def append(self):
+        cmd = 'sudo dd if=/dev/zero of={path} bs=1 count=1 ' \
+              'conv=notrunc oflag=append'.format(path=self.path)
+        return self._test_with_file(cmd,
+                                    'data_digest_mismatch',
+                                    'size_mismatch')
+
+    def truncate(self):
+        cmd = 'sudo dd if=/dev/null of={path}'.format(path=self.path)
+        return self._test_with_file(cmd,
+                                    'data_digest_mismatch',
+                                    'size_mismatch')
+
+    def change_obj(self):
+        cmd = 'sudo dd if=/dev/zero of={path} bs=1 count=1 ' \
+              'conv=notrunc'.format(path=self.path)
+        return self._test_with_file(cmd,
+                                    'data_digest_mismatch')
+
+    @contextlib.contextmanager
+    def rm_omap(self):
+        cmd = ['rmomapkey', self.pool, self.obj, self.omap_key]
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+        yield ('omap_digest_mismatch',)
+        cmd = ['setomapval', self.pool, self.obj,
+               self.omap_key, self.omap_val]
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+
+    @contextlib.contextmanager
+    def add_omap(self):
+        cmd = ['setomapval', self.pool, self.obj, 'badkey', 'badval']
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+        yield ('omap_digest_mismatch',)
+        cmd = ['rmomapkey', self.pool, self.obj, 'badkey']
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+
+    @contextlib.contextmanager
+    def change_omap(self):
+        cmd = ['setomapval', self.pool, self.obj, self.omap_key, 'badval']
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+        yield ('omap_digest_mismatch',)
+        cmd = ['setomapval', self.pool, self.obj, self.omap_key, self.omap_val]
+        self.manager.osd_admin_socket(self.osd_id, cmd)
+
+
+class InconsistentObjChecker:
+    """Check the returned inconsistents/inconsistent info"""
+
+    CEPH_NOSNAP = ctypes.c_uint64(-2).value
+
+    def __init__(self, osd, acting, obj_name):
+        self.osd = osd
+        self.acting = acting
+        self.obj = obj_name
+        assert self.osd in self.acting
+
+    def basic_checks(self, inc):
+        assert inc['object']['name'] == self.obj
+        assert inc['object']['snap'] == self.CEPH_NOSNAP
+        assert len(inc['shards']) == len(self.acting), \
+            "the number of returned shard does not match with the acting set"
+
+    def run(self, check, inc):
+        func = getattr(self, check)
+        func(inc)
+
+    def _get_attrs(self, inc, attr_name):
+        bad_attr = None
+        good_attr = None
+        for shard in inc['shards']:
+            log.info('shard = %r' % shard)
+            log.info('attr = %s' % attr_name)
+            assert 'osd' in shard
+            assert attr_name in shard
+            osd = shard['osd']
+            attr = shard[attr_name]
+            if osd == self.osd:
+                assert bad_attr is None, \
+                    "multiple entries found for the given OSD"
+                bad_attr = attr
+            else:
+                assert osd in self.acting, "shard not in acting set"
+                assert good_attr is None or good_attr == attr, \
+                    "multiple good attrs found"
+                good_attr = attr
+        assert bad_attr is not None, \
+            "good {attr} not found".format(attr=attr_name)
+        assert good_attr is not None, \
+            "bad {attr} not found".format(attr=attr_name)
+        assert good_attr != bad_attr, \
+            "bad attr is identical to the good ones: " \
+            "{0} == {1}".format(good_attr, bad_attr)
+        return bad_attr, good_attr
+
+    def data_digest_mismatch(self, inc):
+        assert inc['data_digest_mismatch'] is True
+        self._get_attrs(inc, 'data_digest')
+
+    def missing(self, inc):
+        assert inc['missing'] is True
+        has_missing, _ = self._get_attrs(inc, 'missing')
+        assert has_missing is True, "the removed shard is not missing"
+
+    def size_mismatch(self, inc):
+        assert inc['size_mismatch'] is True
+        self._get_attrs(inc, 'size')
+
+    def omap_digest_mismatch(self, inc):
+        assert inc['omap_digest_mismatch'] is True
+        self._get_attrs(inc, 'omap_digest')
+
+
+def test_list_inconsistent_obj(ctx, manager, osd_remote, pg, acting, osd_id,
+                               obj_name, obj_path):
+    mon = manager.controller
+    pool = 'rbd'
+    omap_key = 'key'
+    omap_val = 'val'
+    manager.do_rados(mon, ['-p', pool, 'setomapval', obj_name,
+                           omap_key, omap_val])
+    messup = MessUp(manager, osd_remote, pool, osd_id, obj_name, obj_path,
+                    omap_key, omap_val)
+    for test in [messup.rm_omap, messup.add_omap, messup.change_omap,
+                 messup.append, messup.truncate, messup.change_obj,
+                 messup.remove]:
+        with test() as checks:
+            deep_scrub(manager, pg)
+            cmd = 'rados list-inconsistent-pg {pool} ' \
+                  '--format=json'.format(pool=pool)
+            with contextlib.closing(StringIO()) as out:
+                mon.run(args=cmd.split(), stdout=out)
+                pgs = json.loads(out.getvalue())
+            assert pgs == [pg]
+
+            cmd = 'rados list-inconsistent-obj {pg} ' \
+                  '--format=json'.format(pg=pg)
+            with contextlib.closing(StringIO()) as out:
+                mon.run(args=cmd.split(), stdout=out)
+                objs = json.loads(out.getvalue())
+            assert len(objs) == 1
+
+            checker = InconsistentObjChecker(osd_id, acting, obj_name)
+            inc_obj = objs[0]
+            checker.basic_checks(inc_obj)
+            for check in checks:
+                log.info('inc = %r', inc_obj)
+                checker.run(check, inc_obj)
+
+
 def task(ctx, config):
     """
     Test [deep] scrub
@@ -195,5 +373,6 @@ def task(ctx, config):
     log.info('messing with PG %s on osd %d' % (pg, osd))
     test_repair_corrupted_obj(ctx, manager, pg, osd_remote, obj_path)
     test_repair_bad_omap(ctx, manager, pg, osd, obj_name)
-
+    test_list_inconsistent_obj(ctx, manager, osd_remote, pg, acting, osd,
+                               obj_name, obj_path)
     log.info('test successful!')