mirror of
https://github.com/ceph/ceph
synced 2025-01-31 23:44:10 +00:00
ac092f63bf
Test without the fix: 2024-05-16T22:34:21.781 DEBUG:teuthology.orchestra.run.smithi044:> sudo adjust-ulimits ceph-coverage /home/ubuntu/cephtest/archive/coverage timeout 300 ceph --cluster ceph --admin-daemon /var/run/ceph/ceph-mds.a.asok --format=json dump tree /dir 0 ... [ { "accounted_rstat": { "rbytes": 4096, "rctime": "2024-05-16T22:34:15.251864+0000", "rfiles": 1, "rsnaps": 0, "rsubdirs": 1, "version": 0 }, "atime": "2024-05-16T22:34:14.498880+0000", "auth_pins": 0, "auth_state": { "replicas": {} }, "authlock": {}, "backtrace_version": 14, "btime": "2024-05-16T22:34:14.498880+0000", "change_attr": 3, "client_caps": [ { "client_id": 5184, "issued": "pAsLsXsFsx", "last_sent": 4, "pending": "pAsLsXsFsx", "wanted": "pAsLsXsFsxcral" } ], "client_ranges": [], "ctime": "2024-05-16T22:34:15.249864+0000", "damage_flags": 0, "dir_layout": { "dir_hash": 2, "unused1": 0, "unused2": 0, "unused3": 0 }, "dirfrags": [ { "auth_pins": 0, "auth_state": { "replicas": {} }, "committed_version": "0", "committing_version": "0", "dentries": [ { "alternate_name": "bUHUwH9E8uiVaf8xZ+zONcB1CToj53x5aUUnKdnNj5U37zbh28l1AaWwHhbOT3HyzqKjmSKKW1o4odQJc7nF9xrKIB8D3b4qqb2Cs6s7t2106hHhQk5/YV7DtpeNPZnorcTqxPM/hExtWHSS4P+S+Dpwj62hMyh/77sGhiW1Filvv1gQjV+sN/GozPNwHgfleadkUs1OkRkYtgWrCjbKP0MayRtiOLrVTRuYyOp/Qt3+XCIyiS87B9bUcOFjWratF+yR0kpJ0RYriix7NKVkBJ0kGWYSCY+PYjiLeMYJBMQcCxW/nwfVku+m6fgFJvb6pjEFxIk9zT5cunSImsjr", "auth_pins": 0, "auth_state": { "replicas": {} }, "inode": 1099511628283, "is_auth": true, "is_freezing": false, "is_frozen": false, "is_new": false, "is_null": false, "is_primary": true, "is_remote": false, "lock": {}, "nref": 2, "path": "dir/bUHUwH9E8uiVaf8xZ+zONcB1CToj53x5aUUnKdnNj5U37zbh28l1AaWwHhbOT3HyzqKjmSKKW1o4odQJc7nF9xrKIB8D3b4qqb2Cs6s7t2106hHhQk5,YV7DtpeNPZnorcTqxPM,hExtWHSS4P+S+Dpwj62hMyh,77sGhiW1Filvv1gQjV+sN,GozPNwHgfleadkUuZ+PMLCaKQXhuid9WvmHanxJnaabYDLj4VEz+EX2WsG", ... # fail + journal recovery 2024-05-16T22:35:31.077 DEBUG:teuthology.orchestra.run.smithi044:> sudo adjust-ulimits ceph-coverage /home/ubuntu/cephtest/archive/coverage timeout 300 ceph --cluster ceph --admin-daemon /var/run/ceph/ceph-mds.a.asok --format=json dump tree /dir 0 ... [ { "accounted_rstat": { "rbytes": 4096, "rctime": "2024-05-16T22:34:15.251864+0000", "rfiles": 1, "rsnaps": 0, "rsubdirs": 1, "version": 0 }, "atime": "2024-05-16T22:34:14.498880+0000", "auth_pins": 0, "auth_state": { "replicas": {} }, "authlock": {}, "backtrace_version": 14, "btime": "2024-05-16T22:34:14.498880+0000", "change_attr": 3, "client_caps": [], "client_ranges": [], "ctime": "2024-05-16T22:34:15.249864+0000", "damage_flags": 0, "dir_layout": { "dir_hash": 2, "unused1": 0, "unused2": 0, "unused3": 0 }, "dirfrags": [ { "auth_pins": 0, "auth_state": { "replicas": {} }, "committed_version": "5", "committing_version": "5", "dentries": [ { "alternate_name": "", "auth_pins": 0, "auth_state": { "replicas": {} }, "inode": 1099511628283, "is_auth": true, "is_freezing": false, "is_frozen": false, "is_new": false, "is_null": false, "is_primary": true, "is_remote": false, "lock": {}, "nref": 2, "path": "dir/bUHUwH9E8uiVaf8xZ+zONcB1CToj53x5aUUnKdnNj5U37zbh28l1AaWwHhbOT3HyzqKjmSKKW1o4odQJc7nF9xrKIB8D3b4qqb2Cs6s7t2106hHhQk5,YV7DtpeNPZnorcTqxPM,hExtWHSS4P+S+Dpwj62hMyh,77sGhiW1Filvv1gQjV+sN,GozPNwHgfleadkUuZ+PMLCaKQXhuid9WvmHanxJnaabYDLj4VEz+EX2WsG", Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
143 lines
6.0 KiB
Python
143 lines
6.0 KiB
Python
from io import StringIO
|
|
from os.path import basename
|
|
import random
|
|
import string
|
|
|
|
from logging import getLogger
|
|
|
|
from tasks.cephfs.cephfs_test_case import CephFSTestCase
|
|
from tasks.cephfs.xfstests_dev import XFSTestsDev
|
|
|
|
log = getLogger(__name__)
|
|
|
|
class FSCryptTestCase(CephFSTestCase):
|
|
CLIENTS_REQUIRED = 1
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.protector = ''.join(random.choice(string.ascii_letters) for _ in range(8))
|
|
self.key_file = "/tmp/key"
|
|
self.path = "dir/"
|
|
|
|
self.mount_a.run_shell_payload("sudo fscrypt --help")
|
|
self.mount_a.run_shell_payload("sudo fscrypt setup --help")
|
|
self.mount_a.run_shell_payload("sudo fscrypt setup --force --quiet")
|
|
self.mount_a.run_shell_payload("sudo fscrypt status")
|
|
self.mount_a.run_shell_payload(f"sudo fscrypt setup --quiet {self.mount_a.hostfs_mntpt}")
|
|
self.mount_a.run_shell_payload("sudo fscrypt status")
|
|
self.mount_a.run_shell_payload(f"sudo dd if=/dev/urandom of={self.key_file} bs=32 count=1")
|
|
self.mount_a.run_shell_payload(f"mkdir -p {self.path}")
|
|
self.mount_a.run_shell_payload(f"sudo fscrypt encrypt --quiet --source=raw_key --name={self.protector} --no-recovery --skip-unlock --key={self.key_file} {self.path}")
|
|
self.mount_a.run_shell_payload(f"sudo fscrypt unlock --quiet --key=/tmp/key {self.path}")
|
|
|
|
def tearDown(self):
|
|
self.mount_a.run_shell_payload(f"sudo fscrypt purge --force --quiet {self.mount_a.hostfs_mntpt}")
|
|
|
|
super().tearDown()
|
|
|
|
class TestFSCrypt(FSCryptTestCase):
|
|
|
|
def test_fscrypt_basic_mount(self):
|
|
"""
|
|
That fscrypt can be setup and ingest files.
|
|
"""
|
|
|
|
self.mount_a.run_shell_payload(f"cp -av /usr/include {self.path}/")
|
|
|
|
class TestFSCryptRecovery(FSCryptTestCase):
|
|
|
|
def test_fscrypt_journal_recovery(self):
|
|
"""
|
|
That alternate_name can be recovered from the journal.
|
|
"""
|
|
|
|
file = ''.join(random.choice(string.ascii_letters) for _ in range(255))
|
|
|
|
self.mount_a.run_shell_payload(f"cd {self.path} && dd if=/dev/urandom of={file} bs=512 count=1 oflag=sync && sync . && stat {file}")
|
|
|
|
def verify_alternate_name():
|
|
J = self.fs.read_cache("/dir", depth=0)
|
|
self.assertEqual(len(J), 1)
|
|
inode = J[0]
|
|
dirfrags = inode['dirfrags']
|
|
self.assertEqual(len(dirfrags), 1)
|
|
dirfrag = dirfrags[0]
|
|
dentries = dirfrag['dentries']
|
|
self.assertEqual(len(dentries), 1)
|
|
# we don't know it's encrypted name, so we cannot verify that it's {file}
|
|
dentry = dentries[0]
|
|
name = basename(dentry['path'])
|
|
# https://github.com/ceph/ceph-client/blob/fec50db7033ea478773b159e0e2efb135270e3b7/fs/ceph/crypto.h#L65-L90
|
|
self.assertEqual(len(name), 240)
|
|
alternate_name = dentry['alternate_name']
|
|
self.assertGreater(len(alternate_name), 240)
|
|
|
|
verify_alternate_name()
|
|
|
|
self.fs.fail()
|
|
|
|
self.fs.journal_tool(['event', 'recover_dentries', 'list'], 0)
|
|
self.fs.journal_tool(['journal', 'reset', '--yes-i-really-really-mean-it'], 0)
|
|
|
|
self.fs.set_joinable()
|
|
self.fs.wait_for_daemons()
|
|
|
|
verify_alternate_name()
|
|
|
|
self.mount_a.run_shell_payload(f"cd {self.path} && find")
|
|
self.mount_a.run_shell_payload(f"cd {self.path} && stat {file}")
|
|
|
|
|
|
class TestFSCryptXFS(XFSTestsDev):
|
|
|
|
def setup_xfsprogs_devs(self):
|
|
self.install_xfsprogs = True
|
|
|
|
def test_fscrypt_encrypt(self):
|
|
# XXX: check_status is set to False so that we can check for command's
|
|
# failure on our own (since this command doesn't set right error code
|
|
# and error message in some cases) and print custom log messages
|
|
# accordingly.
|
|
proc = self.mount_a.client_remote.run(args=['sudo', 'env', 'DIFF_LENGTH=0',
|
|
'./check', '-g', 'encrypt'], cwd=self.xfstests_repo_path, stdout=StringIO(),
|
|
stderr=StringIO(), timeout=900, check_status=False, omit_sudo=False,
|
|
label='running tests for encrypt from xfstests-dev')
|
|
|
|
if proc.returncode != 0:
|
|
log.info('Command failed.')
|
|
log.info(f'Command return value: {proc.returncode}')
|
|
stdout, stderr = proc.stdout.getvalue(), proc.stderr.getvalue()
|
|
log.info(f'Command stdout -\n{stdout}')
|
|
log.info(f'Command stderr -\n{stderr}')
|
|
|
|
# Currently only the 395,396,397,421,429,435,440,580,593,595 and 598
|
|
# of the 26 test cases will be actually ran, all the others will be
|
|
# skipped for now because of not supporting features in kernel or kceph.
|
|
self.assertEqual(proc.returncode, 0)
|
|
self.assertIn('Passed all 26 tests', stdout)
|
|
|
|
def test_fscrypt_dummy_encryption_with_quick_group(self):
|
|
self.write_local_config('test_dummy_encryption')
|
|
|
|
# XXX: check_status is set to False so that we can check for command's
|
|
# failure on our own (since this command doesn't set right error code
|
|
# and error message in some cases) and print custom log messages
|
|
# accordingly. This will take a long time and set the timeout to 3 hours.
|
|
proc = self.mount_a.client_remote.run(args=['sudo', 'env', 'DIFF_LENGTH=0',
|
|
'./check', '-g', 'quick', '-E', './ceph.exclude'], cwd=self.xfstests_repo_path,
|
|
stdout=StringIO(), stderr=StringIO(), timeout=10800, check_status=False,
|
|
omit_sudo=False, label='running tests for dummy_encryption from xfstests-dev')
|
|
|
|
if proc.returncode != 0:
|
|
log.info('Command failed.')
|
|
log.info(f'Command return value: {proc.returncode}')
|
|
stdout, stderr = proc.stdout.getvalue(), proc.stderr.getvalue()
|
|
log.info(f'Command stdout -\n{stdout}')
|
|
log.info(f'Command stderr -\n{stderr}')
|
|
|
|
# Currently, many test cases will be skipped due to unsupported features,
|
|
# but still will be marked as successful.
|
|
self.assertEqual(proc.returncode, 0)
|
|
self.assertIn('Passed all ', stdout)
|