]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/devices/raw/prepare.py
add stop-gap to fix compat with CPUs not supporting SSE 4.1
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / raw / prepare.py
1 from __future__ import print_function
2 import json
3 import logging
4 import os
5 from textwrap import dedent
6 from ceph_volume.util import prepare as prepare_utils
7 from ceph_volume.util import encryption as encryption_utils
8 from ceph_volume.util import disk
9 from ceph_volume.util import system
10 from ceph_volume import decorators, terminal
11 from ceph_volume.devices.lvm.common import rollback_osd
12 from .common import create_parser
13
14 logger = logging.getLogger(__name__)
15
16 def prepare_dmcrypt(key, device, device_type, fsid):
17 """
18 Helper for devices that are encrypted. The operations needed for
19 block, db, wal, devices are all the same
20 """
21 if not device:
22 return ''
23 kname = disk.lsblk(device)['KNAME']
24 mapping = 'ceph-{}-{}-{}-dmcrypt'.format(fsid, kname, device_type)
25 # format data device
26 encryption_utils.luks_format(
27 key,
28 device
29 )
30 encryption_utils.luks_open(
31 key,
32 device,
33 mapping
34 )
35
36 return '/dev/mapper/{}'.format(mapping)
37
38 def prepare_bluestore(block, wal, db, secrets, osd_id, fsid, tmpfs):
39 """
40 :param block: The name of the logical volume for the bluestore data
41 :param wal: a regular/plain disk or logical volume, to be used for block.wal
42 :param db: a regular/plain disk or logical volume, to be used for block.db
43 :param secrets: A dict with the secrets needed to create the osd (e.g. cephx)
44 :param id_: The OSD id
45 :param fsid: The OSD fsid, also known as the OSD UUID
46 """
47 cephx_secret = secrets.get('cephx_secret', prepare_utils.create_key())
48
49 if secrets.get('dmcrypt_key'):
50 key = secrets['dmcrypt_key']
51 block = prepare_dmcrypt(key, block, 'block', fsid)
52 wal = prepare_dmcrypt(key, wal, 'wal', fsid)
53 db = prepare_dmcrypt(key, db, 'db', fsid)
54
55 # create the directory
56 prepare_utils.create_osd_path(osd_id, tmpfs=tmpfs)
57 # symlink the block
58 prepare_utils.link_block(block, osd_id)
59 # get the latest monmap
60 prepare_utils.get_monmap(osd_id)
61 # write the OSD keyring if it doesn't exist already
62 prepare_utils.write_keyring(osd_id, cephx_secret)
63 # prepare the osd filesystem
64 prepare_utils.osd_mkfs_bluestore(
65 osd_id, fsid,
66 keyring=cephx_secret,
67 wal=wal,
68 db=db
69 )
70
71
72 class Prepare(object):
73
74 help = 'Format a raw device and associate it with a (BlueStore) OSD'
75
76 def __init__(self, argv):
77 self.argv = argv
78 self.osd_id = None
79
80 def safe_prepare(self, args=None):
81 """
82 An intermediate step between `main()` and `prepare()` so that we can
83 capture the `self.osd_id` in case we need to rollback
84
85 :param args: Injected args, usually from `raw create` which compounds
86 both `prepare` and `create`
87 """
88 if args is not None:
89 self.args = args
90 try:
91 self.prepare()
92 except Exception:
93 logger.exception('raw prepare was unable to complete')
94 logger.info('will rollback OSD ID creation')
95 rollback_osd(self.args, self.osd_id)
96 raise
97 dmcrypt_log = 'dmcrypt' if args.dmcrypt else 'clear'
98 terminal.success("ceph-volume raw {} prepare successful for: {}".format(dmcrypt_log, self.args.data))
99
100
101 @decorators.needs_root
102 def prepare(self):
103 secrets = {'cephx_secret': prepare_utils.create_key()}
104 encrypted = 1 if self.args.dmcrypt else 0
105 cephx_lockbox_secret = '' if not encrypted else prepare_utils.create_key()
106
107 if encrypted:
108 secrets['dmcrypt_key'] = os.getenv('CEPH_VOLUME_DMCRYPT_SECRET')
109 secrets['cephx_lockbox_secret'] = cephx_lockbox_secret # dummy value to make `ceph osd new` not complaining
110
111 osd_fsid = system.generate_uuid()
112 crush_device_class = self.args.crush_device_class
113 if crush_device_class:
114 secrets['crush_device_class'] = crush_device_class
115 tmpfs = not self.args.no_tmpfs
116 wal = ""
117 db = ""
118 if self.args.block_wal:
119 wal = self.args.block_wal
120 if self.args.block_db:
121 db = self.args.block_db
122
123 # reuse a given ID if it exists, otherwise create a new ID
124 self.osd_id = prepare_utils.create_id(
125 osd_fsid, json.dumps(secrets))
126
127 prepare_bluestore(
128 self.args.data,
129 wal,
130 db,
131 secrets,
132 self.osd_id,
133 osd_fsid,
134 tmpfs,
135 )
136
137 def main(self):
138 sub_command_help = dedent("""
139 Prepare an OSD by assigning an ID and FSID, registering them with the
140 cluster with an ID and FSID, formatting the volume.
141
142 Once the OSD is ready, an ad-hoc systemd unit will be enabled so that
143 it can later get activated and the OSD daemon can get started.
144
145 ceph-volume raw prepare --bluestore --data {device}
146
147 DB and WAL devices are supported.
148
149 ceph-volume raw prepare --bluestore --data {device} --block.db {device} --block.wal {device}
150
151 """)
152 parser = create_parser(
153 prog='ceph-volume raw prepare',
154 description=sub_command_help,
155 )
156 if not self.argv:
157 print(sub_command_help)
158 return
159 self.args = parser.parse_args(self.argv)
160 if not self.args.bluestore:
161 terminal.error('must specify --bluestore (currently the only supported backend)')
162 raise SystemExit(1)
163 if self.args.dmcrypt and not os.getenv('CEPH_VOLUME_DMCRYPT_SECRET'):
164 terminal.error('encryption was requested (--dmcrypt) but environment variable ' \
165 'CEPH_VOLUME_DMCRYPT_SECRET is not set, you must set ' \
166 'this variable to provide a dmcrypt secret.')
167 raise SystemExit(1)
168
169 self.safe_prepare(self.args)