]> git.proxmox.com Git - ceph.git/blame - ceph/src/ceph-volume/ceph_volume/devices/lvm/prepare.py
update sources to 12.2.2
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / lvm / prepare.py
CommitLineData
d2e6a577
FG
1from __future__ import print_function
2import json
3efd9988 3import uuid
d2e6a577
FG
4from textwrap import dedent
5from ceph_volume.util import prepare as prepare_utils
181888fb
FG
6from ceph_volume.util import system, disk
7from ceph_volume import conf, decorators, terminal
3efd9988 8from ceph_volume.api import lvm as api
d2e6a577
FG
9from .common import prepare_parser
10
11
d2e6a577
FG
12def prepare_filestore(device, journal, secrets, id_=None, fsid=None):
13 """
3efd9988 14 :param device: The name of the logical volume to work with
d2e6a577
FG
15 :param journal: similar to device but can also be a regular/plain disk
16 :param secrets: A dict with the secrets needed to create the osd (e.g. cephx)
17 :param id_: The OSD id
18 :param fsid: The OSD fsid, also known as the OSD UUID
19 """
20 cephx_secret = secrets.get('cephx_secret', prepare_utils.create_key())
21 json_secrets = json.dumps(secrets)
22
23 # allow re-using an existing fsid, in case prepare failed
24 fsid = fsid or system.generate_uuid()
25 # allow re-using an id, in case a prepare failed
26 osd_id = id_ or prepare_utils.create_id(fsid, json_secrets)
27 # create the directory
3efd9988 28 prepare_utils.create_osd_path(osd_id)
d2e6a577
FG
29 # format the device
30 prepare_utils.format_device(device)
31 # mount the data device
32 prepare_utils.mount_osd(device, osd_id)
33 # symlink the journal
34 prepare_utils.link_journal(journal, osd_id)
35 # get the latest monmap
36 prepare_utils.get_monmap(osd_id)
37 # prepare the osd filesystem
3efd9988 38 prepare_utils.osd_mkfs_filestore(osd_id, fsid)
d2e6a577
FG
39 # write the OSD keyring if it doesn't exist already
40 prepare_utils.write_keyring(osd_id, cephx_secret)
41
42
3efd9988
FG
43def prepare_bluestore(block, wal, db, secrets, id_=None, fsid=None):
44 """
45 :param block: The name of the logical volume for the bluestore data
46 :param wal: a regular/plain disk or logical volume, to be used for block.wal
47 :param db: a regular/plain disk or logical volume, to be used for block.db
48 :param secrets: A dict with the secrets needed to create the osd (e.g. cephx)
49 :param id_: The OSD id
50 :param fsid: The OSD fsid, also known as the OSD UUID
51 """
52 cephx_secret = secrets.get('cephx_secret', prepare_utils.create_key())
53 json_secrets = json.dumps(secrets)
54
55 # allow re-using an existing fsid, in case prepare failed
56 fsid = fsid or system.generate_uuid()
57 # allow re-using an id, in case a prepare failed
58 osd_id = id_ or prepare_utils.create_id(fsid, json_secrets)
59 # create the directory
60 prepare_utils.create_osd_path(osd_id, tmpfs=True)
61 # symlink the block
62 prepare_utils.link_block(block, osd_id)
63 # get the latest monmap
64 prepare_utils.get_monmap(osd_id)
65 # write the OSD keyring if it doesn't exist already
66 prepare_utils.write_keyring(osd_id, cephx_secret)
67 # prepare the osd filesystem
68 prepare_utils.osd_mkfs_bluestore(
69 osd_id, fsid,
70 keyring=cephx_secret,
71 wal=wal,
72 db=db
73 )
d2e6a577
FG
74
75
76class Prepare(object):
77
78 help = 'Format an LVM device and associate it with an OSD'
79
80 def __init__(self, argv):
81 self.argv = argv
82
3efd9988 83 def get_ptuuid(self, argument):
181888fb
FG
84 uuid = disk.get_partuuid(argument)
85 if not uuid:
86 terminal.error('blkid could not detect a PARTUUID for device: %s' % argument)
3efd9988 87 raise RuntimeError('unable to use device')
181888fb
FG
88 return uuid
89
3efd9988 90 def get_lv(self, argument):
b5b8bbf5 91 """
3efd9988
FG
92 Perform some parsing of the command-line value so that the process
93 can determine correctly if it got a device path or an lv.
94
95 :param argument: The command-line value that will need to be split to
96 retrieve the actual lv
b5b8bbf5
FG
97 """
98 try:
99 vg_name, lv_name = argument.split('/')
100 except (ValueError, AttributeError):
101 return None
102 return api.get_lv(lv_name=lv_name, vg_name=vg_name)
103
3efd9988
FG
104 def setup_device(self, device_type, device_name, tags):
105 """
106 Check if ``device`` is an lv, if so, set the tags, making sure to
107 update the tags with the lv_uuid and lv_path which the incoming tags
108 will not have.
109
110 If the device is not a logical volume, then retrieve the partition UUID
111 by querying ``blkid``
112 """
113 if device_name is None:
114 return '', '', tags
115 tags['ceph.type'] = device_type
116 lv = self.get_lv(device_name)
117 if lv:
118 uuid = lv.lv_uuid
119 path = lv.lv_path
120 tags['ceph.%s_uuid' % device_type] = uuid
121 tags['ceph.%s_device' % device_type] = path
122 lv.set_tags(tags)
123 else:
124 # otherwise assume this is a regular disk partition
125 uuid = self.get_ptuuid(device_name)
126 path = device_name
127 tags['ceph.%s_uuid' % device_type] = uuid
128 tags['ceph.%s_device' % device_type] = path
129 return path, uuid, tags
130
131 def prepare_device(self, arg, device_type, cluster_fsid, osd_fsid):
132 """
133 Check if ``arg`` is a device or partition to create an LV out of it
134 with a distinct volume group name, assigning LV tags on it and
135 ultimately, returning the logical volume object. Failing to detect
136 a device or partition will result in error.
137
138 :param arg: The value of ``--data`` when parsing args
139 :param device_type: Usually, either ``data`` or ``block`` (filestore vs. bluestore)
140 :param cluster_fsid: The cluster fsid/uuid
141 :param osd_fsid: The OSD fsid/uuid
142 """
143 if disk.is_partition(arg) or disk.is_device(arg):
144 # we must create a vg, and then a single lv
145 vg_name = "ceph-%s" % cluster_fsid
146 if api.get_vg(vg_name=vg_name):
147 # means we already have a group for this, make a different one
148 # XXX this could end up being annoying for an operator, maybe?
149 vg_name = "ceph-%s" % str(uuid.uuid4())
150 api.create_vg(vg_name, arg)
151 lv_name = "osd-%s-%s" % (device_type, osd_fsid)
152 return api.create_lv(
153 lv_name,
154 vg_name, # the volume group
155 tags={'ceph.type': device_type})
156 else:
157 error = [
158 'Cannot use device (%s).',
159 'A vg/lv path or an existing device is needed' % arg]
160 raise RuntimeError(' '.join(error))
161
162 raise RuntimeError('no data logical volume found with: %s' % arg)
163
d2e6a577
FG
164 @decorators.needs_root
165 def prepare(self, args):
166 # FIXME we don't allow re-using a keyring, we always generate one for the
167 # OSD, this needs to be fixed. This could either be a file (!) or a string
168 # (!!) or some flags that we would need to compound into a dict so that we
169 # can convert to JSON (!!!)
170 secrets = {'cephx_secret': prepare_utils.create_key()}
171
172 cluster_fsid = conf.ceph.get('global', 'fsid')
3efd9988 173 osd_fsid = args.osd_fsid or system.generate_uuid()
d2e6a577 174 # allow re-using an id, in case a prepare failed
3efd9988 175 osd_id = args.osd_id or prepare_utils.create_id(osd_fsid, json.dumps(secrets))
d2e6a577 176 if args.filestore:
b5b8bbf5
FG
177 if not args.journal:
178 raise RuntimeError('--journal is required when using --filestore')
b5b8bbf5 179
3efd9988
FG
180 data_lv = self.get_lv(args.data)
181 if not data_lv:
182 data_lv = self.prepare_device(args.data, 'data', cluster_fsid, osd_fsid)
181888fb 183
3efd9988
FG
184 tags = {
185 'ceph.osd_fsid': osd_fsid,
d2e6a577
FG
186 'ceph.osd_id': osd_id,
187 'ceph.cluster_fsid': cluster_fsid,
3efd9988 188 'ceph.cluster_name': conf.cluster,
d2e6a577 189 'ceph.data_device': data_lv.lv_path,
181888fb 190 'ceph.data_uuid': data_lv.lv_uuid,
3efd9988
FG
191 }
192
193 journal_device, journal_uuid, tags = self.setup_device('journal', args.journal, tags)
194
195 tags['ceph.type'] = 'data'
196 data_lv.set_tags(tags)
d2e6a577
FG
197
198 prepare_filestore(
199 data_lv.lv_path,
200 journal_device,
201 secrets,
202 id_=osd_id,
3efd9988 203 fsid=osd_fsid,
d2e6a577
FG
204 )
205 elif args.bluestore:
3efd9988
FG
206 block_lv = self.get_lv(args.data)
207 if not block_lv:
208 block_lv = self.prepare_device(args.data, 'block', cluster_fsid, osd_fsid)
209
210 tags = {
211 'ceph.osd_fsid': osd_fsid,
212 'ceph.osd_id': osd_id,
213 'ceph.cluster_fsid': cluster_fsid,
214 'ceph.cluster_name': conf.cluster,
215 'ceph.block_device': block_lv.lv_path,
216 'ceph.block_uuid': block_lv.lv_uuid,
217 }
218
219 wal_device, wal_uuid, tags = self.setup_device('wal', args.block_wal, tags)
220 db_device, db_uuid, tags = self.setup_device('db', args.block_db, tags)
221
222 tags['ceph.type'] = 'block'
223 block_lv.set_tags(tags)
224
225 prepare_bluestore(
226 block_lv.lv_path,
227 wal_device,
228 db_device,
229 secrets,
230 id_=osd_id,
231 fsid=osd_fsid,
232 )
d2e6a577
FG
233
234 def main(self):
235 sub_command_help = dedent("""
236 Prepare an OSD by assigning an ID and FSID, registering them with the
237 cluster with an ID and FSID, formatting and mounting the volume, and
238 finally by adding all the metadata to the logical volumes using LVM
239 tags, so that it can later be discovered.
240
241 Once the OSD is ready, an ad-hoc systemd unit will be enabled so that
242 it can later get activated and the OSD daemon can get started.
243
244 Most basic Usage looks like (journal will be collocated from the same volume group):
245
246 ceph-volume lvm prepare --data {volume group name}
247
248
249 Example calls for supported scenarios:
250
251 Dedicated volume group for Journal(s)
252 -------------------------------------
253
254 Existing logical volume (lv) or device:
255
3efd9988 256 ceph-volume lvm prepare --filestore --data {vg/lv} --journal /path/to/device
d2e6a577
FG
257
258 Or:
259
3efd9988
FG
260 ceph-volume lvm prepare --filestore --data {vg/lv} --journal {vg/lv}
261
262 Existing block device, that will be made a group and logical volume:
263
264 ceph-volume lvm prepare --filestore --data /path/to/device --journal {vg/lv}
265
266 Bluestore
267 ---------
268
269 Existing logical volume (lv):
270
271 ceph-volume lvm prepare --bluestore --data {vg/lv}
272
273 Existing block device, that will be made a group and logical volume:
d2e6a577 274
3efd9988 275 ceph-volume lvm prepare --bluestore --data /path/to/device
d2e6a577 276
3efd9988 277 Optionally, can consume db and wal devices or logical volumes:
d2e6a577 278
3efd9988 279 ceph-volume lvm prepare --bluestore --data {vg/lv} --block.wal {device} --block-db {vg/lv}
d2e6a577
FG
280 """)
281 parser = prepare_parser(
282 prog='ceph-volume lvm prepare',
283 description=sub_command_help,
284 )
285 if len(self.argv) == 0:
286 print(sub_command_help)
287 return
288 args = parser.parse_args(self.argv)
3efd9988
FG
289 # Default to bluestore here since defaulting it in add_argument may
290 # cause both to be True
291 if args.bluestore is None and args.filestore is None:
292 args.bluestore = True
d2e6a577 293 self.prepare(args)