summaryrefslogtreecommitdiffstats
path: root/qa/tasks/ceph_fuse.py
diff options
context:
space:
mode:
Diffstat (limited to 'qa/tasks/ceph_fuse.py')
-rw-r--r--qa/tasks/ceph_fuse.py175
1 files changed, 175 insertions, 0 deletions
diff --git a/qa/tasks/ceph_fuse.py b/qa/tasks/ceph_fuse.py
new file mode 100644
index 000000000..d2db29732
--- /dev/null
+++ b/qa/tasks/ceph_fuse.py
@@ -0,0 +1,175 @@
+"""
+Ceph FUSE client task
+"""
+
+import contextlib
+import logging
+
+from teuthology import misc
+from tasks.cephfs.fuse_mount import FuseMount
+
+log = logging.getLogger(__name__)
+
+
+@contextlib.contextmanager
+def task(ctx, config):
+ """
+ Mount/unmount a ``ceph-fuse`` client.
+
+ The config is optional and defaults to mounting on all clients. If
+ a config is given, it is expected to be a list of clients to do
+ this operation on. This lets you e.g. set up one client with
+ ``ceph-fuse`` and another with ``kclient``.
+
+ ``brxnet`` should be a Private IPv4 Address range, default range is
+ [192.168.0.0/16]
+
+ Example that mounts all clients::
+
+ tasks:
+ - ceph:
+ - ceph-fuse:
+ - interactive:
+ - brxnet: [192.168.0.0/16]
+
+ Example that uses both ``kclient` and ``ceph-fuse``::
+
+ tasks:
+ - ceph:
+ - ceph-fuse: [client.0]
+ - kclient: [client.1]
+ - interactive:
+
+ Example that enables valgrind:
+
+ tasks:
+ - ceph:
+ - ceph-fuse:
+ client.0:
+ valgrind: [--tool=memcheck, --leak-check=full, --show-reachable=yes]
+ - interactive:
+
+ Example that stops an already-mounted client:
+
+ ::
+
+ tasks:
+ - ceph:
+ - ceph-fuse: [client.0]
+ - ... do something that requires the FS mounted ...
+ - ceph-fuse:
+ client.0:
+ mounted: false
+ - ... do something that requires the FS unmounted ...
+
+ Example that adds more generous wait time for mount (for virtual machines):
+
+ tasks:
+ - ceph:
+ - ceph-fuse:
+ client.0:
+ mount_wait: 60 # default is 0, do not wait before checking /sys/
+ mount_timeout: 120 # default is 30, give up if /sys/ is not populated
+ - interactive:
+
+ :param ctx: Context
+ :param config: Configuration
+ """
+ log.info('Running ceph_fuse task...')
+
+ if config is None:
+ ids = misc.all_roles_of_type(ctx.cluster, 'client')
+ client_roles = [f'client.{id_}' for id_ in ids]
+ config = dict([r, dict()] for r in client_roles)
+ elif isinstance(config, list):
+ client_roles = config
+ config = dict([r, dict()] for r in client_roles)
+ elif isinstance(config, dict):
+ client_roles = filter(lambda x: 'client.' in x, config.keys())
+ else:
+ raise ValueError(f"Invalid config object: {config} ({config.__class__})")
+ log.info(f"config is {config}")
+
+ clients = list(misc.get_clients(ctx=ctx, roles=client_roles))
+ testdir = misc.get_testdir(ctx)
+ all_mounts = getattr(ctx, 'mounts', {})
+ mounted_by_me = {}
+ skipped = {}
+ remotes = set()
+
+ brxnet = config.get("brxnet", None)
+
+ # Construct any new FuseMount instances
+ overrides = ctx.config.get('overrides', {}).get('ceph-fuse', {})
+ top_overrides = dict(filter(lambda x: 'client.' not in x[0], overrides.items()))
+ for id_, remote in clients:
+ entity = f"client.{id_}"
+ client_config = config.get(entity)
+ if client_config is None:
+ client_config = {}
+ # top level overrides
+ misc.deep_merge(client_config, top_overrides)
+ # mount specific overrides
+ client_config_overrides = overrides.get(entity)
+ misc.deep_merge(client_config, client_config_overrides)
+ log.info(f"{entity} config is {client_config}")
+
+ remotes.add(remote)
+ auth_id = client_config.get("auth_id", id_)
+ cephfs_name = client_config.get("cephfs_name")
+
+ skip = client_config.get("skip", False)
+ if skip:
+ skipped[id_] = skip
+ continue
+
+ if id_ not in all_mounts:
+ fuse_mount = FuseMount(ctx=ctx, client_config=client_config,
+ test_dir=testdir, client_id=auth_id,
+ client_remote=remote, brxnet=brxnet,
+ cephfs_name=cephfs_name)
+ all_mounts[id_] = fuse_mount
+ else:
+ # Catch bad configs where someone has e.g. tried to use ceph-fuse and kcephfs for the same client
+ assert isinstance(all_mounts[id_], FuseMount)
+
+ if not config.get("disabled", False) and client_config.get('mounted', True):
+ mounted_by_me[id_] = {"config": client_config, "mount": all_mounts[id_]}
+
+ ctx.mounts = all_mounts
+
+ # Umount any pre-existing clients that we have not been asked to mount
+ for client_id in set(all_mounts.keys()) - set(mounted_by_me.keys()) - set(skipped.keys()):
+ mount = all_mounts[client_id]
+ if mount.is_mounted():
+ mount.umount_wait()
+
+ for remote in remotes:
+ FuseMount.cleanup_stale_netnses_and_bridge(remote)
+
+ # Mount any clients we have been asked to (default to mount all)
+ log.info('Mounting ceph-fuse clients...')
+ for info in mounted_by_me.values():
+ config = info["config"]
+ mount_x = info['mount']
+ if config.get("mount_path"):
+ mount_x.cephfs_mntpt = config.get("mount_path")
+ if config.get("mountpoint"):
+ mount_x.hostfs_mntpt = config.get("mountpoint")
+ mount_x.mount(createfs=False)
+
+ for info in mounted_by_me.values():
+ info["mount"].wait_until_mounted()
+
+ try:
+ yield all_mounts
+ finally:
+ log.info('Unmounting ceph-fuse clients...')
+
+ for info in mounted_by_me.values():
+ # Conditional because an inner context might have umounted it
+ mount = info["mount"]
+ if mount.is_mounted():
+ mount.umount_wait()
+ for remote in remotes:
+ FuseMount.cleanup_stale_netnses_and_bridge(remote)