]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 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 | # Assemble mon addresses | |
76 | remotes_and_roles = ctx.cluster.remotes.items() | |
77 | roles = [roles for (remote_, roles) in remotes_and_roles] | |
78 | ips = [remote_.ssh.get_transport().getpeername()[0] | |
79 | for (remote_, _) in remotes_and_roles] | |
80 | mons = misc.get_mons(roles, ips).values() | |
81 | ||
82 | mounts = {} | |
83 | for id_, remote in clients: | |
84 | client_config = config.get("client.%s" % id_) | |
85 | if client_config is None: | |
86 | client_config = {} | |
87 | ||
88 | if config.get("disabled", False) or not client_config.get('mounted', True): | |
89 | continue | |
90 | ||
91 | kernel_mount = KernelMount( | |
92 | mons, | |
93 | test_dir, | |
94 | id_, | |
95 | remote, | |
96 | ctx.teuthology_config.get('ipmi_user', None), | |
97 | ctx.teuthology_config.get('ipmi_password', None), | |
98 | ctx.teuthology_config.get('ipmi_domain', None) | |
99 | ) | |
100 | ||
101 | mounts[id_] = kernel_mount | |
102 | ||
103 | if client_config.get('debug', False): | |
104 | remote.run(args=["sudo", "bash", "-c", "echo 'module ceph +p' > /sys/kernel/debug/dynamic_debug/control"]) | |
105 | remote.run(args=["sudo", "bash", "-c", "echo 'module libceph +p' > /sys/kernel/debug/dynamic_debug/control"]) | |
106 | ||
107 | kernel_mount.mount() | |
108 | ||
109 | ||
110 | def umount_all(): | |
111 | log.info('Unmounting kernel clients...') | |
112 | ||
113 | forced = False | |
114 | for mount in mounts.values(): | |
115 | if mount.is_mounted(): | |
116 | try: | |
117 | mount.umount() | |
118 | except (CommandFailedError, MaxWhileTries): | |
119 | log.warn("Ordinary umount failed, forcing...") | |
120 | forced = True | |
121 | mount.umount_wait(force=True) | |
122 | ||
123 | return forced | |
124 | ||
125 | ctx.mounts = mounts | |
126 | try: | |
127 | yield mounts | |
128 | except: | |
129 | umount_all() # ignore forced retval, we are already in error handling | |
130 | finally: | |
131 | ||
132 | forced = umount_all() | |
133 | if forced: | |
134 | # The context managers within the kclient manager worked (i.e. | |
135 | # the test workload passed) but for some reason we couldn't | |
136 | # umount, so turn this into a test failure. | |
137 | raise RuntimeError("Kernel mounts did not umount cleanly") |