]> git.proxmox.com Git - ceph.git/blame - ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / lvm / activate.py
CommitLineData
d2e6a577
FG
1from __future__ import print_function
2import argparse
3efd9988
FG
3import logging
4import os
d2e6a577 5from textwrap import dedent
20effc67 6from ceph_volume import process, conf, decorators, terminal, configuration
181888fb 7from ceph_volume.util import system, disk
3efd9988 8from ceph_volume.util import prepare as prepare_utils
b32b8144 9from ceph_volume.util import encryption as encryption_utils
d2e6a577 10from ceph_volume.systemd import systemctl
3efd9988 11from ceph_volume.api import lvm as api
94b18763 12from .listing import direct_report
3efd9988
FG
13
14
15logger = logging.getLogger(__name__)
d2e6a577
FG
16
17
d2e6a577 18
f6b5b4d7 19def get_osd_device_path(osd_lvs, device_type, dmcrypt_secret=None):
3efd9988 20 """
f6b5b4d7
TL
21 ``device_type`` can be one of ``db``, ``wal`` or ``block`` so that we can
22 query LVs on system and fallback to querying the uuid if that is not
23 present.
3efd9988 24
f6b5b4d7
TL
25 Return a path if possible, failing to do that a ``None``, since some of
26 these devices are optional.
3efd9988 27 """
f6b5b4d7
TL
28 osd_block_lv = None
29 for lv in osd_lvs:
30 if lv.tags.get('ceph.type') == 'block':
31 osd_block_lv = lv
32 break
33 if osd_block_lv:
34 is_encrypted = osd_block_lv.tags.get('ceph.encrypted', '0') == '1'
35 logger.debug('Found block device (%s) with encryption: %s', osd_block_lv.name, is_encrypted)
36 uuid_tag = 'ceph.%s_uuid' % device_type
37 device_uuid = osd_block_lv.tags.get(uuid_tag)
38 if not device_uuid:
39 return None
40
41 device_lv = None
42 for lv in osd_lvs:
43 if lv.tags.get('ceph.type') == device_type:
44 device_lv = lv
45 break
3efd9988 46 if device_lv:
b32b8144
FG
47 if is_encrypted:
48 encryption_utils.luks_open(dmcrypt_secret, device_lv.lv_path, device_uuid)
49 return '/dev/mapper/%s' % device_uuid
3efd9988 50 return device_lv.lv_path
494da23a
TL
51
52 # this could be a regular device, so query it with blkid
53 physical_device = disk.get_device_from_partuuid(device_uuid)
54 if physical_device:
55 if is_encrypted:
b32b8144
FG
56 encryption_utils.luks_open(dmcrypt_secret, physical_device, device_uuid)
57 return '/dev/mapper/%s' % device_uuid
494da23a
TL
58 return physical_device
59
60 raise RuntimeError('could not find %s with uuid %s' % (device_type, device_uuid))
3efd9988
FG
61
62
20effc67 63def activate_bluestore(osd_lvs, no_systemd=False, no_tmpfs=False):
f6b5b4d7
TL
64 for lv in osd_lvs:
65 if lv.tags.get('ceph.type') == 'block':
66 osd_block_lv = lv
67 break
68 else:
94b18763 69 raise RuntimeError('could not find a bluestore OSD to activate')
f6b5b4d7
TL
70
71 is_encrypted = osd_block_lv.tags.get('ceph.encrypted', '0') == '1'
b32b8144 72 dmcrypt_secret = None
f6b5b4d7
TL
73 osd_id = osd_block_lv.tags['ceph.osd_id']
74 conf.cluster = osd_block_lv.tags['ceph.cluster_name']
75 osd_fsid = osd_block_lv.tags['ceph.osd_fsid']
20effc67
TL
76 configuration.load_ceph_conf_path(osd_block_lv.tags['ceph.cluster_name'])
77 configuration.load()
3efd9988
FG
78
79 # mount on tmpfs the osd directory
80 osd_path = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id)
81 if not system.path_is_mounted(osd_path):
82 # mkdir -p and mount as tmpfs
20effc67 83 prepare_utils.create_osd_path(osd_id, tmpfs=not no_tmpfs)
3efd9988
FG
84 # XXX This needs to be removed once ceph-bluestore-tool can deal with
85 # symlinks that exist in the osd dir
86 for link_name in ['block', 'block.db', 'block.wal']:
87 link_path = os.path.join(osd_path, link_name)
88 if os.path.exists(link_path):
89 os.unlink(os.path.join(osd_path, link_name))
b32b8144
FG
90 # encryption is handled here, before priming the OSD dir
91 if is_encrypted:
f6b5b4d7
TL
92 osd_lv_path = '/dev/mapper/%s' % osd_block_lv.lv_uuid
93 lockbox_secret = osd_block_lv.tags['ceph.cephx_lockbox_secret']
b32b8144
FG
94 encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret)
95 dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid)
f6b5b4d7 96 encryption_utils.luks_open(dmcrypt_secret, osd_block_lv.lv_path, osd_block_lv.lv_uuid)
b32b8144 97 else:
f6b5b4d7 98 osd_lv_path = osd_block_lv.lv_path
b32b8144 99
f6b5b4d7
TL
100 db_device_path = get_osd_device_path(osd_lvs, 'db', dmcrypt_secret=dmcrypt_secret)
101 wal_device_path = get_osd_device_path(osd_lvs, 'wal', dmcrypt_secret=dmcrypt_secret)
b32b8144 102
f64942e4
AA
103 # Once symlinks are removed, the osd dir can be 'primed again. chown first,
104 # regardless of what currently exists so that ``prime-osd-dir`` can succeed
105 # even if permissions are somehow messed up
106 system.chown(osd_path)
1adf2230 107 prime_command = [
b32b8144
FG
108 'ceph-bluestore-tool', '--cluster=%s' % conf.cluster,
109 'prime-osd-dir', '--dev', osd_lv_path,
20effc67 110 '--path', osd_path, '--no-mon-config']
1adf2230
AA
111
112 process.run(prime_command)
3efd9988
FG
113 # always re-do the symlink regardless if it exists, so that the block,
114 # block.wal, and block.db devices that may have changed can be mapped
115 # correctly every time
b32b8144 116 process.run(['ln', '-snf', osd_lv_path, os.path.join(osd_path, 'block')])
3efd9988
FG
117 system.chown(os.path.join(osd_path, 'block'))
118 system.chown(osd_path)
119 if db_device_path:
120 destination = os.path.join(osd_path, 'block.db')
b32b8144 121 process.run(['ln', '-snf', db_device_path, destination])
3efd9988 122 system.chown(db_device_path)
28e407b8 123 system.chown(destination)
3efd9988
FG
124 if wal_device_path:
125 destination = os.path.join(osd_path, 'block.wal')
b32b8144 126 process.run(['ln', '-snf', wal_device_path, destination])
3efd9988 127 system.chown(wal_device_path)
28e407b8 128 system.chown(destination)
3efd9988 129
94b18763
FG
130 if no_systemd is False:
131 # enable the ceph-volume unit for this OSD
132 systemctl.enable_volume(osd_id, osd_fsid, 'lvm')
3efd9988 133
1adf2230
AA
134 # enable the OSD
135 systemctl.enable_osd(osd_id)
136
94b18763
FG
137 # start the OSD
138 systemctl.start_osd(osd_id)
b32b8144 139 terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
d2e6a577
FG
140
141
142class Activate(object):
143
144 help = 'Discover and mount the LVM device associated with an OSD ID and start the Ceph OSD'
145
146 def __init__(self, argv):
147 self.argv = argv
148
149 @decorators.needs_root
94b18763
FG
150 def activate_all(self, args):
151 listed_osds = direct_report()
152 osds = {}
153 for osd_id, devices in listed_osds.items():
154 # the metadata for all devices in each OSD will contain
155 # the FSID which is required for activation
156 for device in devices:
157 fsid = device.get('tags', {}).get('ceph.osd_fsid')
158 if fsid:
159 osds[fsid] = osd_id
160 break
161 if not osds:
162 terminal.warning('Was unable to find any OSDs to activate')
163 terminal.warning('Verify OSDs are present with "ceph-volume lvm list"')
164 return
165 for osd_fsid, osd_id in osds.items():
a4b75251 166 if not args.no_systemd and systemctl.osd_is_active(osd_id):
94b18763
FG
167 terminal.warning(
168 'OSD ID %s FSID %s process is active. Skipping activation' % (osd_id, osd_fsid)
169 )
170 else:
171 terminal.info('Activating OSD ID %s FSID %s' % (osd_id, osd_fsid))
172 self.activate(args, osd_id=osd_id, osd_fsid=osd_fsid)
173
174 @decorators.needs_root
175 def activate(self, args, osd_id=None, osd_fsid=None):
176 """
177 :param args: The parsed arguments coming from the CLI
f6b5b4d7
TL
178 :param osd_id: When activating all, this gets populated with an
179 existing OSD ID
180 :param osd_fsid: When activating all, this gets populated with an
181 existing OSD FSID
94b18763 182 """
f6b5b4d7
TL
183 osd_id = osd_id if osd_id else args.osd_id
184 osd_fsid = osd_fsid if osd_fsid else args.osd_fsid
94b18763 185
94b18763 186 if osd_id and osd_fsid:
f6b5b4d7
TL
187 tags = {'ceph.osd_id': osd_id, 'ceph.osd_fsid': osd_fsid}
188 elif not osd_id and osd_fsid:
189 tags = {'ceph.osd_fsid': osd_fsid}
522d829b
TL
190 elif osd_id and not osd_fsid:
191 raise RuntimeError('could not activate osd.{}, please provide the '
192 'osd_fsid too'.format(osd_id))
193 else:
194 raise RuntimeError('Please provide both osd_id and osd_fsid')
f6b5b4d7 195 lvs = api.get_lvs(tags=tags)
d2e6a577 196 if not lvs:
f6b5b4d7
TL
197 raise RuntimeError('could not find osd.%s with osd_fsid %s' %
198 (osd_id, osd_fsid))
199
3efd9988
FG
200 # This argument is only available when passed in directly or via
201 # systemd, not when ``create`` is being used
05a536ef 202 # placeholder when a new objectstore support will be added
3efd9988
FG
203 if getattr(args, 'auto_detect_objectstore', False):
204 logger.info('auto detecting objectstore')
f6b5b4d7 205 return activate_bluestore(lvs, args.no_systemd)
20effc67 206
05a536ef 207 # explicit 'objectstore' flags take precedence
20effc67
TL
208 if getattr(args, 'bluestore', False):
209 activate_bluestore(lvs, args.no_systemd, getattr(args, 'no_tmpfs', False))
20effc67
TL
210 elif any('ceph.block_device' in lv.tags for lv in lvs):
211 activate_bluestore(lvs, args.no_systemd, getattr(args, 'no_tmpfs', False))
d2e6a577
FG
212
213 def main(self):
214 sub_command_help = dedent("""
215 Activate OSDs by discovering them with LVM and mounting them in their
216 appropriate destination:
217
218 ceph-volume lvm activate {ID} {FSID}
219
220 The lvs associated with the OSD need to have been prepared previously,
221 so that all needed tags and metadata exist.
222
94b18763
FG
223 When migrating OSDs, or a multiple-osd activation is needed, the
224 ``--all`` flag can be used instead of the individual ID and FSID:
225
226 ceph-volume lvm activate --all
227
d2e6a577
FG
228 """)
229 parser = argparse.ArgumentParser(
230 prog='ceph-volume lvm activate',
231 formatter_class=argparse.RawDescriptionHelpFormatter,
232 description=sub_command_help,
233 )
234
235 parser.add_argument(
236 'osd_id',
237 metavar='ID',
238 nargs='?',
239 help='The ID of the OSD, usually an integer, like 0'
240 )
241 parser.add_argument(
242 'osd_fsid',
243 metavar='FSID',
244 nargs='?',
245 help='The FSID of the OSD, similar to a SHA1'
246 )
3efd9988
FG
247 parser.add_argument(
248 '--auto-detect-objectstore',
249 action='store_true',
250 help='Autodetect the objectstore by inspecting the OSD',
251 )
d2e6a577
FG
252 parser.add_argument(
253 '--bluestore',
3efd9988 254 action='store_true',
20effc67 255 help='force bluestore objectstore activation',
d2e6a577 256 )
94b18763
FG
257 parser.add_argument(
258 '--all',
259 dest='activate_all',
260 action='store_true',
261 help='Activate all OSDs found in the system',
262 )
263 parser.add_argument(
264 '--no-systemd',
265 dest='no_systemd',
266 action='store_true',
267 help='Skip creating and enabling systemd units and starting OSD services',
d2e6a577 268 )
20effc67
TL
269 parser.add_argument(
270 '--no-tmpfs',
271 action='store_true',
272 help='Do not use a tmpfs mount for OSD data dir'
273 )
d2e6a577
FG
274 if len(self.argv) == 0:
275 print(sub_command_help)
276 return
277 args = parser.parse_args(self.argv)
94b18763
FG
278 if args.activate_all:
279 self.activate_all(args)
280 else:
281 self.activate(args)