2014-10-28 17:12:02 +00:00
|
|
|
import json
|
2014-07-02 15:43:16 +00:00
|
|
|
import logging
|
2020-01-27 06:07:44 +00:00
|
|
|
|
|
|
|
from io import StringIO
|
2014-10-28 17:12:02 +00:00
|
|
|
from textwrap import dedent
|
2020-01-27 06:07:44 +00:00
|
|
|
|
2014-09-15 22:41:34 +00:00
|
|
|
from teuthology.orchestra.run import CommandFailedError
|
2014-07-02 15:43:16 +00:00
|
|
|
from teuthology.orchestra import run
|
2017-02-01 00:25:44 +00:00
|
|
|
from teuthology.contextutil import MaxWhileTries
|
2020-01-27 06:07:44 +00:00
|
|
|
|
2020-03-24 08:33:22 +00:00
|
|
|
from tasks.cephfs.mount import CephFSMount
|
2014-07-02 15:43:16 +00:00
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2017-02-01 00:25:44 +00:00
|
|
|
UMOUNT_TIMEOUT = 300
|
|
|
|
|
|
|
|
|
2014-07-02 15:43:16 +00:00
|
|
|
class KernelMount(CephFSMount):
|
2020-01-27 06:07:44 +00:00
|
|
|
def __init__(self, ctx, test_dir, client_id, client_remote,
|
|
|
|
client_keyring_path=None, hostfs_mntpt=None,
|
|
|
|
cephfs_name=None, cephfs_mntpt=None, brxnet=None):
|
|
|
|
super(KernelMount, self).__init__(ctx=ctx, test_dir=test_dir,
|
|
|
|
client_id=client_id, client_remote=client_remote,
|
|
|
|
client_keyring_path=client_keyring_path, hostfs_mntpt=hostfs_mntpt,
|
|
|
|
cephfs_name=cephfs_name, cephfs_mntpt=cephfs_mntpt, brxnet=brxnet)
|
|
|
|
|
|
|
|
def mount(self, mntopts=[], createfs=True, **kwargs):
|
|
|
|
self.update_attrs(**kwargs)
|
|
|
|
self.assert_and_log_minimum_mount_details()
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2020-03-03 13:31:29 +00:00
|
|
|
self.setup_netns()
|
2018-07-12 13:25:53 +00:00
|
|
|
|
2020-01-27 06:07:44 +00:00
|
|
|
# TODO: don't call setupfs() from within mount(), since it's
|
|
|
|
# absurd. The proper order should be: create FS first and then
|
|
|
|
# call mount().
|
|
|
|
if createfs:
|
|
|
|
self.setupfs(name=self.cephfs_name)
|
|
|
|
if not self.cephfs_mntpt:
|
|
|
|
self.cephfs_mntpt = '/'
|
2014-07-02 15:43:16 +00:00
|
|
|
|
2020-01-27 06:07:44 +00:00
|
|
|
stderr = StringIO()
|
|
|
|
try:
|
|
|
|
self.client_remote.run(args=['mkdir', '-p', self.hostfs_mntpt],
|
|
|
|
timeout=(5*60), stderr=stderr)
|
|
|
|
except CommandFailedError:
|
|
|
|
if 'file exists' not in stderr.getvalue().lower():
|
|
|
|
raise
|
2015-11-09 13:15:21 +00:00
|
|
|
|
2020-01-27 06:07:44 +00:00
|
|
|
opts = 'name=' + self.client_id
|
|
|
|
if self.client_keyring_path and self.client_id is not None:
|
|
|
|
opts += 'secret=' + self.get_key_from_keyfile()
|
|
|
|
opts += ',norequire_active_mds,conf=' + self.config_path
|
2016-11-06 22:01:00 +00:00
|
|
|
|
2020-01-27 06:07:44 +00:00
|
|
|
if self.cephfs_name is not None:
|
|
|
|
opts += ",mds_namespace={0}".format(self.cephfs_name)
|
2016-11-06 22:01:00 +00:00
|
|
|
|
2020-01-27 06:07:44 +00:00
|
|
|
if mntopts:
|
|
|
|
opts += ',' + ','.join(mntopts)
|
2019-10-28 07:39:44 +00:00
|
|
|
|
2014-07-02 15:43:16 +00:00
|
|
|
self.client_remote.run(
|
|
|
|
args=[
|
|
|
|
'sudo',
|
|
|
|
'adjust-ulimits',
|
|
|
|
'ceph-coverage',
|
|
|
|
'{tdir}/archive/coverage'.format(tdir=self.test_dir),
|
2020-03-03 13:31:29 +00:00
|
|
|
'nsenter',
|
|
|
|
'--net=/var/run/netns/{0}'.format(self.netns_name),
|
2019-09-17 13:30:16 +00:00
|
|
|
'/bin/mount',
|
|
|
|
'-t',
|
|
|
|
'ceph',
|
2020-01-27 06:07:44 +00:00
|
|
|
':' + self.cephfs_mntpt,
|
|
|
|
self.hostfs_mntpt,
|
2014-07-02 15:43:16 +00:00
|
|
|
'-v',
|
|
|
|
'-o',
|
2016-11-06 22:01:00 +00:00
|
|
|
opts
|
2014-07-02 15:43:16 +00:00
|
|
|
],
|
2018-10-10 20:33:46 +00:00
|
|
|
timeout=(30*60),
|
2014-07-02 15:43:16 +00:00
|
|
|
)
|
|
|
|
|
2014-09-15 22:41:34 +00:00
|
|
|
self.client_remote.run(
|
2020-01-27 06:07:44 +00:00
|
|
|
args=['sudo', 'chmod', '1777', self.hostfs_mntpt], timeout=(5*60))
|
2014-09-15 22:41:34 +00:00
|
|
|
|
|
|
|
self.mounted = True
|
|
|
|
|
2017-01-09 12:47:37 +00:00
|
|
|
def umount(self, force=False):
|
2020-03-05 01:59:04 +00:00
|
|
|
if not self.is_mounted():
|
2020-05-07 12:33:41 +00:00
|
|
|
self.cleanup()
|
2020-03-05 01:59:04 +00:00
|
|
|
return
|
|
|
|
|
2014-07-02 15:43:16 +00:00
|
|
|
log.debug('Unmounting client client.{id}...'.format(id=self.client_id))
|
2017-01-09 12:47:37 +00:00
|
|
|
|
2017-07-19 07:32:37 +00:00
|
|
|
try:
|
2020-01-27 06:07:44 +00:00
|
|
|
cmd=['sudo', 'umount', self.hostfs_mntpt]
|
2020-06-19 06:21:59 +00:00
|
|
|
if force:
|
|
|
|
cmd.append('-f')
|
|
|
|
self.client_remote.run(args=cmd, timeout=(15*60), omit_sudo=False)
|
2017-07-19 07:32:37 +00:00
|
|
|
except Exception as e:
|
2020-06-19 06:21:59 +00:00
|
|
|
self.client_remote.run(
|
|
|
|
args=['sudo', run.Raw('PATH=/usr/sbin:$PATH'), 'lsof',
|
|
|
|
run.Raw(';'), 'ps', 'auxf'],
|
|
|
|
timeout=(15*60), omit_sudo=False)
|
2017-07-19 07:32:37 +00:00
|
|
|
raise e
|
2017-01-09 12:47:37 +00:00
|
|
|
|
2014-09-15 22:41:34 +00:00
|
|
|
self.mounted = False
|
2020-03-03 13:31:29 +00:00
|
|
|
self.cleanup()
|
2014-07-17 20:35:22 +00:00
|
|
|
|
2018-05-11 12:26:43 +00:00
|
|
|
def umount_wait(self, force=False, require_clean=False, timeout=900):
|
2014-09-15 22:41:34 +00:00
|
|
|
"""
|
|
|
|
Unlike the fuse client, the kernel client's umount is immediate
|
|
|
|
"""
|
2016-08-30 12:02:28 +00:00
|
|
|
if not self.is_mounted():
|
2020-05-07 12:33:41 +00:00
|
|
|
self.cleanup()
|
2016-08-30 12:02:28 +00:00
|
|
|
return
|
|
|
|
|
2014-09-15 22:41:34 +00:00
|
|
|
try:
|
2017-01-09 12:47:37 +00:00
|
|
|
self.umount(force)
|
2017-02-01 00:25:44 +00:00
|
|
|
except (CommandFailedError, MaxWhileTries):
|
2014-09-15 22:41:34 +00:00
|
|
|
if not force:
|
|
|
|
raise
|
|
|
|
|
2020-03-03 13:31:29 +00:00
|
|
|
# force delete the netns and umount
|
2020-06-19 06:21:59 +00:00
|
|
|
self.client_remote.run(args=['sudo', 'umount', '-f', '-l',
|
|
|
|
self.mountpoint],
|
|
|
|
timeout=(15*60), omit_sudo=False)
|
2020-03-03 13:31:29 +00:00
|
|
|
|
|
|
|
self.mounted = False
|
|
|
|
self.cleanup()
|
2014-07-17 20:35:22 +00:00
|
|
|
|
|
|
|
def wait_until_mounted(self):
|
2014-09-15 22:41:34 +00:00
|
|
|
"""
|
|
|
|
Unlike the fuse client, the kernel client is up and running as soon
|
|
|
|
as the initial mount() function returns.
|
|
|
|
"""
|
|
|
|
assert self.mounted
|
2014-07-17 20:35:22 +00:00
|
|
|
|
|
|
|
def teardown(self):
|
|
|
|
super(KernelMount, self).teardown()
|
2014-09-15 22:41:34 +00:00
|
|
|
if self.mounted:
|
|
|
|
self.umount()
|
|
|
|
|
2014-10-28 17:12:02 +00:00
|
|
|
def _find_debug_dir(self):
|
2014-09-15 22:41:34 +00:00
|
|
|
"""
|
2014-10-28 17:12:02 +00:00
|
|
|
Find the debugfs folder for this mount
|
2014-09-15 22:41:34 +00:00
|
|
|
"""
|
2014-10-28 17:12:02 +00:00
|
|
|
pyscript = dedent("""
|
|
|
|
import glob
|
|
|
|
import os
|
|
|
|
import json
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2014-10-28 17:12:02 +00:00
|
|
|
def get_id_to_dir():
|
|
|
|
result = {}
|
|
|
|
for dir in glob.glob("/sys/kernel/debug/ceph/*"):
|
|
|
|
mds_sessions_lines = open(os.path.join(dir, "mds_sessions")).readlines()
|
|
|
|
client_id = mds_sessions_lines[1].split()[1].strip('"')
|
|
|
|
|
|
|
|
result[client_id] = dir
|
|
|
|
return result
|
|
|
|
|
2019-10-07 14:09:05 +00:00
|
|
|
print(json.dumps(get_id_to_dir()))
|
2014-10-28 17:12:02 +00:00
|
|
|
""")
|
|
|
|
|
2019-12-16 01:46:13 +00:00
|
|
|
output = self.client_remote.sh([
|
2019-12-19 03:51:52 +00:00
|
|
|
'sudo', 'python3', '-c', pyscript
|
2019-12-16 01:46:13 +00:00
|
|
|
], timeout=(5*60))
|
|
|
|
client_id_to_dir = json.loads(output)
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2014-10-28 17:12:02 +00:00
|
|
|
try:
|
|
|
|
return client_id_to_dir[self.client_id]
|
|
|
|
except KeyError:
|
|
|
|
log.error("Client id '{0}' debug dir not found (clients seen were: {1})".format(
|
|
|
|
self.client_id, ",".join(client_id_to_dir.keys())
|
|
|
|
))
|
|
|
|
raise
|
|
|
|
|
|
|
|
def _read_debug_file(self, filename):
|
|
|
|
debug_dir = self._find_debug_dir()
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2014-10-28 17:12:02 +00:00
|
|
|
pyscript = dedent("""
|
|
|
|
import os
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2019-10-07 14:09:05 +00:00
|
|
|
print(open(os.path.join("{debug_dir}", "{filename}")).read())
|
2014-10-28 17:12:02 +00:00
|
|
|
""").format(debug_dir=debug_dir, filename=filename)
|
2014-09-15 22:41:34 +00:00
|
|
|
|
2019-12-16 01:46:13 +00:00
|
|
|
output = self.client_remote.sh([
|
2019-12-19 03:51:52 +00:00
|
|
|
'sudo', 'python3', '-c', pyscript
|
2019-12-16 01:46:13 +00:00
|
|
|
], timeout=(5*60))
|
|
|
|
return output
|
2014-10-28 17:12:02 +00:00
|
|
|
|
|
|
|
def get_global_id(self):
|
|
|
|
"""
|
|
|
|
Look up the CephFS client ID for this mount, using debugfs.
|
|
|
|
"""
|
|
|
|
|
|
|
|
assert self.mounted
|
|
|
|
|
|
|
|
mds_sessions = self._read_debug_file("mds_sessions")
|
|
|
|
lines = mds_sessions.split("\n")
|
|
|
|
return int(lines[0].split()[1])
|
|
|
|
|
|
|
|
def get_osd_epoch(self):
|
|
|
|
"""
|
|
|
|
Return 2-tuple of osd_epoch, osd_epoch_barrier
|
|
|
|
"""
|
|
|
|
osd_map = self._read_debug_file("osdmap")
|
|
|
|
lines = osd_map.split("\n")
|
2017-04-09 17:13:29 +00:00
|
|
|
first_line_tokens = lines[0].split()
|
|
|
|
epoch, barrier = int(first_line_tokens[1]), int(first_line_tokens[3])
|
2014-10-28 17:12:02 +00:00
|
|
|
|
2017-04-09 17:13:29 +00:00
|
|
|
return epoch, barrier
|