]>
Commit | Line | Data |
---|---|---|
1 | """ | |
2 | Mount/unmount a ``kernel`` client. | |
3 | """ | |
4 | import contextlib | |
5 | import logging | |
6 | ||
7 | from teuthology.misc import deep_merge | |
8 | from teuthology.orchestra.run import CommandFailedError | |
9 | from teuthology import misc | |
10 | from teuthology.contextutil import MaxWhileTries | |
11 | from tasks.cephfs.kernel_mount import KernelMount | |
12 | ||
13 | log = logging.getLogger(__name__) | |
14 | ||
15 | @contextlib.contextmanager | |
16 | def task(ctx, config): | |
17 | """ | |
18 | Mount/unmount a ``kernel`` client. | |
19 | ||
20 | The config is optional and defaults to mounting on all clients. If | |
21 | a config is given, it is expected to be a list of clients to do | |
22 | this operation on. This lets you e.g. set up one client with | |
23 | ``ceph-fuse`` and another with ``kclient``. | |
24 | ||
25 | Example that mounts all clients:: | |
26 | ||
27 | tasks: | |
28 | - ceph: | |
29 | - kclient: | |
30 | - interactive: | |
31 | ||
32 | Example that uses both ``kclient` and ``ceph-fuse``:: | |
33 | ||
34 | tasks: | |
35 | - ceph: | |
36 | - ceph-fuse: [client.0] | |
37 | - kclient: [client.1] | |
38 | - interactive: | |
39 | ||
40 | ||
41 | Pass a dictionary instead of lists to specify per-client config: | |
42 | ||
43 | tasks: | |
44 | -kclient: | |
45 | client.0: | |
46 | debug: true | |
47 | ||
48 | :param ctx: Context | |
49 | :param config: Configuration | |
50 | """ | |
51 | log.info('Mounting kernel clients...') | |
52 | assert config is None or isinstance(config, list) or isinstance(config, dict), \ | |
53 | "task kclient got invalid config" | |
54 | ||
55 | if config is None: | |
56 | config = ['client.{id}'.format(id=id_) | |
57 | for id_ in misc.all_roles_of_type(ctx.cluster, 'client')] | |
58 | ||
59 | if isinstance(config, list): | |
60 | client_roles = config | |
61 | config = dict([r, dict()] for r in client_roles) | |
62 | elif isinstance(config, dict): | |
63 | client_roles = filter(lambda x: 'client.' in x, config.keys()) | |
64 | else: | |
65 | raise ValueError("Invalid config object: {0} ({1})".format(config, config.__class__)) | |
66 | ||
67 | # config has been converted to a dict by this point | |
68 | overrides = ctx.config.get('overrides', {}) | |
69 | deep_merge(config, overrides.get('kclient', {})) | |
70 | ||
71 | clients = list(misc.get_clients(ctx=ctx, roles=client_roles)) | |
72 | ||
73 | test_dir = misc.get_testdir(ctx) | |
74 | ||
75 | mounts = {} | |
76 | for id_, remote in clients: | |
77 | client_config = config.get("client.%s" % id_) | |
78 | if client_config is None: | |
79 | client_config = {} | |
80 | ||
81 | if config.get("disabled", False) or not client_config.get('mounted', True): | |
82 | continue | |
83 | ||
84 | kernel_mount = KernelMount( | |
85 | ctx, | |
86 | test_dir, | |
87 | id_, | |
88 | remote, | |
89 | ctx.teuthology_config.get('ipmi_user', None), | |
90 | ctx.teuthology_config.get('ipmi_password', None), | |
91 | ctx.teuthology_config.get('ipmi_domain', None) | |
92 | ) | |
93 | ||
94 | mounts[id_] = kernel_mount | |
95 | ||
96 | if client_config.get('debug', False): | |
97 | remote.run(args=["sudo", "bash", "-c", "echo 'module ceph +p' > /sys/kernel/debug/dynamic_debug/control"]) | |
98 | remote.run(args=["sudo", "bash", "-c", "echo 'module libceph +p' > /sys/kernel/debug/dynamic_debug/control"]) | |
99 | ||
100 | kernel_mount.mount() | |
101 | ||
102 | ||
103 | def umount_all(): | |
104 | log.info('Unmounting kernel clients...') | |
105 | ||
106 | forced = False | |
107 | for mount in mounts.values(): | |
108 | if mount.is_mounted(): | |
109 | try: | |
110 | mount.umount() | |
111 | except (CommandFailedError, MaxWhileTries): | |
112 | log.warning("Ordinary umount failed, forcing...") | |
113 | forced = True | |
114 | mount.umount_wait(force=True) | |
115 | ||
116 | return forced | |
117 | ||
118 | ctx.mounts = mounts | |
119 | try: | |
120 | yield mounts | |
121 | except: | |
122 | umount_all() # ignore forced retval, we are already in error handling | |
123 | finally: | |
124 | ||
125 | forced = umount_all() | |
126 | if forced: | |
127 | # The context managers within the kclient manager worked (i.e. | |
128 | # the test workload passed) but for some reason we couldn't | |
129 | # umount, so turn this into a test failure. | |
130 | raise RuntimeError("Kernel mounts did not umount cleanly") |