qa: add test to verify recovery of alternate_name from journal

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>
This commit is contained in:
Patrick Donnelly 2024-05-14 22:39:05 -04:00
parent 4b4cb5474c
commit ac092f63bf
No known key found for this signature in database
GPG Key ID: FA47FD0B0367D313
2 changed files with 92 additions and 3 deletions

View File

@ -1,3 +1,10 @@
overrides:
install:
extra_system_packages:
rpm:
- fscrypt
deb:
- fscrypt
tasks:
- cephfs_test_runner:
fail_on_skip: false

View File

@ -1,13 +1,95 @@
from io import StringIO
from os.path import basename
import random
import string
from logging import getLogger
from io import StringIO
from tasks.cephfs.cephfs_test_case import CephFSTestCase
from tasks.cephfs.xfstests_dev import XFSTestsDev
log = getLogger(__name__)
class FSCryptTestCase(CephFSTestCase):
CLIENTS_REQUIRED = 1
class TestFscrypt(XFSTestsDev):
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