]> git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/cephfs/kernel_mount.py
update sources to 12.2.7
[ceph.git] / ceph / qa / tasks / cephfs / kernel_mount.py
1 from StringIO import StringIO
2 import json
3 import logging
4 from textwrap import dedent
5 from teuthology.orchestra.run import CommandFailedError
6 from teuthology import misc
7
8 from teuthology.orchestra import remote as orchestra_remote
9 from teuthology.orchestra import run
10 from teuthology.contextutil import MaxWhileTries
11 from .mount import CephFSMount
12
13 log = logging.getLogger(__name__)
14
15
16 UMOUNT_TIMEOUT = 300
17
18
19 class KernelMount(CephFSMount):
20 def __init__(self, mons, test_dir, client_id, client_remote,
21 ipmi_user, ipmi_password, ipmi_domain):
22 super(KernelMount, self).__init__(test_dir, client_id, client_remote)
23 self.mons = mons
24
25 self.mounted = False
26 self.ipmi_user = ipmi_user
27 self.ipmi_password = ipmi_password
28 self.ipmi_domain = ipmi_domain
29
30 def write_secret_file(self, remote, role, keyring, filename):
31 """
32 Stash the keyring in the filename specified.
33 """
34 remote.run(
35 args=[
36 'adjust-ulimits',
37 'ceph-coverage',
38 '{tdir}/archive/coverage'.format(tdir=self.test_dir),
39 'ceph-authtool',
40 '--name={role}'.format(role=role),
41 '--print-key',
42 keyring,
43 run.Raw('>'),
44 filename,
45 ],
46 )
47
48 def mount(self, mount_path=None, mount_fs_name=None):
49 log.info('Mounting kclient client.{id} at {remote} {mnt}...'.format(
50 id=self.client_id, remote=self.client_remote, mnt=self.mountpoint))
51
52 keyring = self.get_keyring_path()
53 secret = '{tdir}/ceph.data/client.{id}.secret'.format(tdir=self.test_dir, id=self.client_id)
54 self.write_secret_file(self.client_remote, 'client.{id}'.format(id=self.client_id),
55 keyring, secret)
56
57 self.client_remote.run(
58 args=[
59 'mkdir',
60 '--',
61 self.mountpoint,
62 ],
63 )
64
65 if mount_path is None:
66 mount_path = "/"
67
68 opts = 'name={id},secretfile={secret},norequire_active_mds'.format(id=self.client_id,
69 secret=secret)
70
71 if mount_fs_name is not None:
72 opts += ",mds_namespace={0}".format(mount_fs_name)
73
74 self.client_remote.run(
75 args=[
76 'sudo',
77 'adjust-ulimits',
78 'ceph-coverage',
79 '{tdir}/archive/coverage'.format(tdir=self.test_dir),
80 '/sbin/mount.ceph',
81 '{mons}:{mount_path}'.format(mons=','.join(self.mons), mount_path=mount_path),
82 self.mountpoint,
83 '-v',
84 '-o',
85 opts
86 ],
87 )
88
89 self.client_remote.run(
90 args=['sudo', 'chmod', '1777', self.mountpoint])
91
92 self.mounted = True
93
94 def umount(self, force=False):
95 log.debug('Unmounting client client.{id}...'.format(id=self.client_id))
96
97 cmd=['sudo', 'umount', self.mountpoint]
98 if force:
99 cmd.append('-f')
100
101 try:
102 self.client_remote.run(args=cmd)
103 except Exception as e:
104 self.client_remote.run(args=[
105 'sudo',
106 run.Raw('PATH=/usr/sbin:$PATH'),
107 'lsof',
108 run.Raw(';'),
109 'ps', 'auxf',
110 ])
111 raise e
112
113 rproc = self.client_remote.run(
114 args=[
115 'rmdir',
116 '--',
117 self.mountpoint,
118 ],
119 wait=False
120 )
121 run.wait([rproc], UMOUNT_TIMEOUT)
122 self.mounted = False
123
124 def cleanup(self):
125 pass
126
127 def umount_wait(self, force=False, require_clean=False, timeout=900):
128 """
129 Unlike the fuse client, the kernel client's umount is immediate
130 """
131 if not self.is_mounted():
132 return
133
134 try:
135 self.umount(force)
136 except (CommandFailedError, MaxWhileTries):
137 if not force:
138 raise
139
140 self.kill()
141 self.kill_cleanup()
142
143 self.mounted = False
144
145 def is_mounted(self):
146 return self.mounted
147
148 def wait_until_mounted(self):
149 """
150 Unlike the fuse client, the kernel client is up and running as soon
151 as the initial mount() function returns.
152 """
153 assert self.mounted
154
155 def teardown(self):
156 super(KernelMount, self).teardown()
157 if self.mounted:
158 self.umount()
159
160 def kill(self):
161 """
162 The Ceph kernel client doesn't have a mechanism to kill itself (doing
163 that in side the kernel would be weird anyway), so we reboot the whole node
164 to get the same effect.
165
166 We use IPMI to reboot, because we don't want the client to send any
167 releases of capabilities.
168 """
169
170 con = orchestra_remote.getRemoteConsole(self.client_remote.hostname,
171 self.ipmi_user,
172 self.ipmi_password,
173 self.ipmi_domain)
174 con.power_off()
175
176 self.mounted = False
177
178 def kill_cleanup(self):
179 assert not self.mounted
180
181 con = orchestra_remote.getRemoteConsole(self.client_remote.hostname,
182 self.ipmi_user,
183 self.ipmi_password,
184 self.ipmi_domain)
185 con.power_on()
186
187 # Wait for node to come back up after reboot
188 misc.reconnect(None, 300, [self.client_remote])
189
190 # Remove mount directory
191 self.client_remote.run(
192 args=[
193 'rmdir',
194 '--',
195 self.mountpoint,
196 ],
197 )
198
199 def _find_debug_dir(self):
200 """
201 Find the debugfs folder for this mount
202 """
203 pyscript = dedent("""
204 import glob
205 import os
206 import json
207
208 def get_id_to_dir():
209 result = {}
210 for dir in glob.glob("/sys/kernel/debug/ceph/*"):
211 mds_sessions_lines = open(os.path.join(dir, "mds_sessions")).readlines()
212 client_id = mds_sessions_lines[1].split()[1].strip('"')
213
214 result[client_id] = dir
215 return result
216
217 print json.dumps(get_id_to_dir())
218 """)
219
220 p = self.client_remote.run(args=[
221 'sudo', 'python', '-c', pyscript
222 ], stdout=StringIO())
223 client_id_to_dir = json.loads(p.stdout.getvalue())
224
225 try:
226 return client_id_to_dir[self.client_id]
227 except KeyError:
228 log.error("Client id '{0}' debug dir not found (clients seen were: {1})".format(
229 self.client_id, ",".join(client_id_to_dir.keys())
230 ))
231 raise
232
233 def _read_debug_file(self, filename):
234 debug_dir = self._find_debug_dir()
235
236 pyscript = dedent("""
237 import os
238
239 print open(os.path.join("{debug_dir}", "{filename}")).read()
240 """).format(debug_dir=debug_dir, filename=filename)
241
242 p = self.client_remote.run(args=[
243 'sudo', 'python', '-c', pyscript
244 ], stdout=StringIO())
245 return p.stdout.getvalue()
246
247 def get_global_id(self):
248 """
249 Look up the CephFS client ID for this mount, using debugfs.
250 """
251
252 assert self.mounted
253
254 mds_sessions = self._read_debug_file("mds_sessions")
255 lines = mds_sessions.split("\n")
256 return int(lines[0].split()[1])
257
258 def get_osd_epoch(self):
259 """
260 Return 2-tuple of osd_epoch, osd_epoch_barrier
261 """
262 osd_map = self._read_debug_file("osdmap")
263 lines = osd_map.split("\n")
264 first_line_tokens = lines[0].split()
265 epoch, barrier = int(first_line_tokens[1]), int(first_line_tokens[3])
266
267 return epoch, barrier