]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/util/prepare.py
update sources to v12.2.4
[ceph.git] / ceph / src / ceph-volume / ceph_volume / util / prepare.py
1 """
2 These utilities for prepare provide all the pieces needed to prepare a device
3 but also a compounded ("single call") helper to do them in order. Some plugins
4 may want to change some part of the process, while others might want to consume
5 the single-call helper
6 """
7 import os
8 import logging
9 import json
10 from ceph_volume import process, conf
11 from ceph_volume.util import system, constants
12
13 logger = logging.getLogger(__name__)
14
15
16 def create_key():
17 stdout, stderr, returncode = process.call(
18 ['ceph-authtool', '--gen-print-key'],
19 show_command=True)
20 if returncode != 0:
21 raise RuntimeError('Unable to generate a new auth key')
22 return ' '.join(stdout).strip()
23
24
25 def write_keyring(osd_id, secret, keyring_name='keyring', name=None):
26 """
27 Create a keyring file with the ``ceph-authtool`` utility. Constructs the
28 path over well-known conventions for the OSD, and allows any other custom
29 ``name`` to be set.
30
31 :param osd_id: The ID for the OSD to be used
32 :param secret: The key to be added as (as a string)
33 :param name: Defaults to 'osd.{ID}' but can be used to add other client
34 names, specifically for 'lockbox' type of keys
35 :param keyring_name: Alternative keyring name, for supporting other
36 types of keys like for lockbox
37 """
38 osd_keyring = '/var/lib/ceph/osd/%s-%s/%s' % (conf.cluster, osd_id, keyring_name)
39 name = name or 'osd.%s' % str(osd_id)
40 process.run(
41 [
42 'ceph-authtool', osd_keyring,
43 '--create-keyring',
44 '--name', name,
45 '--add-key', secret
46 ])
47 system.chown(osd_keyring)
48
49
50 def create_id(fsid, json_secrets, osd_id=None):
51 """
52 :param fsid: The osd fsid to create, always required
53 :param json_secrets: a json-ready object with whatever secrets are wanted
54 to be passed to the monitor
55 :param osd_id: Reuse an existing ID from an OSD that's been destroyed, if the
56 id does not exist in the cluster a new ID will be created
57 """
58 bootstrap_keyring = '/var/lib/ceph/bootstrap-osd/%s.keyring' % conf.cluster
59 cmd = [
60 'ceph',
61 '--cluster', conf.cluster,
62 '--name', 'client.bootstrap-osd',
63 '--keyring', bootstrap_keyring,
64 '-i', '-',
65 'osd', 'new', fsid
66 ]
67 if check_id(osd_id):
68 cmd.append(osd_id)
69 stdout, stderr, returncode = process.call(
70 cmd,
71 stdin=json_secrets,
72 show_command=True
73 )
74 if returncode != 0:
75 raise RuntimeError('Unable to create a new OSD id')
76 return ' '.join(stdout).strip()
77
78
79 def check_id(osd_id):
80 """
81 Checks to see if an osd ID exists or not. Returns True
82 if it does exist, False if it doesn't.
83
84 :param osd_id: The osd ID to check
85 """
86 if osd_id is None:
87 return False
88 bootstrap_keyring = '/var/lib/ceph/bootstrap-osd/%s.keyring' % conf.cluster
89 stdout, stderr, returncode = process.call(
90 [
91 'ceph',
92 '--cluster', conf.cluster,
93 '--name', 'client.bootstrap-osd',
94 '--keyring', bootstrap_keyring,
95 'osd',
96 'tree',
97 '-f', 'json',
98 ],
99 show_command=True
100 )
101 if returncode != 0:
102 raise RuntimeError('Unable check if OSD id exists: %s' % osd_id)
103
104 output = json.loads(''.join(stdout).strip())
105 osds = output['nodes']
106 return any([str(osd['id']) == str(osd_id) for osd in osds])
107
108
109 def mount_tmpfs(path):
110 process.run([
111 'mount',
112 '-t',
113 'tmpfs', 'tmpfs',
114 path
115 ])
116
117
118 def create_osd_path(osd_id, tmpfs=False):
119 path = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id)
120 system.mkdir_p('/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id))
121 if tmpfs:
122 mount_tmpfs(path)
123
124
125 def format_device(device):
126 # only supports xfs
127 command = ['mkfs', '-t', 'xfs']
128
129 # get the mkfs options if any for xfs,
130 # fallback to the default options defined in constants.mkfs
131 flags = conf.ceph.get_list(
132 'osd',
133 'osd_mkfs_options_xfs',
134 default=constants.mkfs.get('xfs'),
135 split=' ',
136 )
137
138 # always force
139 if '-f' not in flags:
140 flags.insert(0, '-f')
141
142 command.extend(flags)
143 command.append(device)
144 process.run(command)
145
146
147 def _normalize_mount_flags(flags):
148 """
149 Mount flag options have to be a single string, separated by a comma. If the
150 flags are separated by spaces, or with commas and spaces in ceph.conf, the
151 mount options will be passed incorrectly.
152
153 This will help when parsing ceph.conf values return something like::
154
155 ["rw,", "exec,"]
156
157 Or::
158
159 [" rw ,", "exec"]
160
161 :param flags: A list of flags, or a single string of mount flags
162 """
163 if isinstance(flags, list):
164 # ensure that spaces and commas are removed so that they can join
165 # correctly
166 return ','.join([f.strip().strip(',') for f in flags if f])
167
168 # split them, clean them, and join them back again
169 flags = flags.strip().split(' ')
170 return ','.join(
171 [f.strip().strip(',') for f in flags if f]
172 )
173
174
175 def mount_osd(device, osd_id):
176 destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id)
177 command = ['mount', '-t', 'xfs', '-o']
178 flags = conf.ceph.get_list(
179 'osd',
180 'osd_mount_options_xfs',
181 default=constants.mount.get('xfs'),
182 split=' ',
183 )
184 command.append(_normalize_mount_flags(flags))
185 command.append(device)
186 command.append(destination)
187 process.run(command)
188
189
190 def _link_device(device, device_type, osd_id):
191 """
192 Allow linking any device type in an OSD directory. ``device`` must the be
193 source, with an absolute path and ``device_type`` will be the destination
194 name, like 'journal', or 'block'
195 """
196 device_path = '/var/lib/ceph/osd/%s-%s/%s' % (
197 conf.cluster,
198 osd_id,
199 device_type
200 )
201 command = ['ln', '-s', device, device_path]
202 system.chown(device)
203
204 process.run(command)
205
206
207 def link_journal(journal_device, osd_id):
208 _link_device(journal_device, 'journal', osd_id)
209
210
211 def link_block(block_device, osd_id):
212 _link_device(block_device, 'block', osd_id)
213
214
215 def link_wal(wal_device, osd_id):
216 _link_device(wal_device, 'block.wal', osd_id)
217
218
219 def link_db(db_device, osd_id):
220 _link_device(db_device, 'block.db', osd_id)
221
222
223 def get_monmap(osd_id):
224 """
225 Before creating the OSD files, a monmap needs to be retrieved so that it
226 can be used to tell the monitor(s) about the new OSD. A call will look like::
227
228 ceph --cluster ceph --name client.bootstrap-osd \
229 --keyring /var/lib/ceph/bootstrap-osd/ceph.keyring \
230 mon getmap -o /var/lib/ceph/osd/ceph-0/activate.monmap
231 """
232 path = '/var/lib/ceph/osd/%s-%s/' % (conf.cluster, osd_id)
233 bootstrap_keyring = '/var/lib/ceph/bootstrap-osd/%s.keyring' % conf.cluster
234 monmap_destination = os.path.join(path, 'activate.monmap')
235
236 process.run([
237 'ceph',
238 '--cluster', conf.cluster,
239 '--name', 'client.bootstrap-osd',
240 '--keyring', bootstrap_keyring,
241 'mon', 'getmap', '-o', monmap_destination
242 ])
243
244
245 def osd_mkfs_bluestore(osd_id, fsid, keyring=None, wal=False, db=False):
246 """
247 Create the files for the OSD to function. A normal call will look like:
248
249 ceph-osd --cluster ceph --mkfs --mkkey -i 0 \
250 --monmap /var/lib/ceph/osd/ceph-0/activate.monmap \
251 --osd-data /var/lib/ceph/osd/ceph-0 \
252 --osd-uuid 8d208665-89ae-4733-8888-5d3bfbeeec6c \
253 --keyring /var/lib/ceph/osd/ceph-0/keyring \
254 --setuser ceph --setgroup ceph
255
256 In some cases it is required to use the keyring, when it is passed in as
257 a keywork argument it is used as part of the ceph-osd command
258 """
259 path = '/var/lib/ceph/osd/%s-%s/' % (conf.cluster, osd_id)
260 monmap = os.path.join(path, 'activate.monmap')
261
262 system.chown(path)
263
264 base_command = [
265 'ceph-osd',
266 '--cluster', conf.cluster,
267 # undocumented flag, sets the `type` file to contain 'bluestore'
268 '--osd-objectstore', 'bluestore',
269 '--mkfs',
270 '-i', osd_id,
271 '--monmap', monmap,
272 ]
273
274 supplementary_command = [
275 '--osd-data', path,
276 '--osd-uuid', fsid,
277 '--setuser', 'ceph',
278 '--setgroup', 'ceph'
279 ]
280
281 if keyring is not None:
282 base_command.extend(['--keyfile', '-'])
283
284 if wal:
285 base_command.extend(
286 ['--bluestore-block-wal-path', wal]
287 )
288 system.chown(wal)
289
290 if db:
291 base_command.extend(
292 ['--bluestore-block-db-path', db]
293 )
294 system.chown(db)
295
296 command = base_command + supplementary_command
297
298 process.call(command, stdin=keyring, show_command=True)
299
300
301 def osd_mkfs_filestore(osd_id, fsid):
302 """
303 Create the files for the OSD to function. A normal call will look like:
304
305 ceph-osd --cluster ceph --mkfs --mkkey -i 0 \
306 --monmap /var/lib/ceph/osd/ceph-0/activate.monmap \
307 --osd-data /var/lib/ceph/osd/ceph-0 \
308 --osd-journal /var/lib/ceph/osd/ceph-0/journal \
309 --osd-uuid 8d208665-89ae-4733-8888-5d3bfbeeec6c \
310 --keyring /var/lib/ceph/osd/ceph-0/keyring \
311 --setuser ceph --setgroup ceph
312
313 """
314 path = '/var/lib/ceph/osd/%s-%s/' % (conf.cluster, osd_id)
315 monmap = os.path.join(path, 'activate.monmap')
316 journal = os.path.join(path, 'journal')
317
318 system.chown(journal)
319 system.chown(path)
320
321 process.run([
322 'ceph-osd',
323 '--cluster', conf.cluster,
324 # undocumented flag, sets the `type` file to contain 'filestore'
325 '--osd-objectstore', 'filestore',
326 '--mkfs',
327 '-i', osd_id,
328 '--monmap', monmap,
329 '--osd-data', path,
330 '--osd-journal', journal,
331 '--osd-uuid', fsid,
332 '--setuser', 'ceph',
333 '--setgroup', 'ceph'
334 ])