]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/devices/lvm/strategies/bluestore.py
update sources to 12.2.8
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / lvm / strategies / bluestore.py
1 from __future__ import print_function
2 import json
3 from uuid import uuid4
4 from ceph_volume.util import disk
5 from ceph_volume.api import lvm
6 from . import validators
7 from ceph_volume.devices.lvm.create import Create
8 from ceph_volume.util import templates
9
10
11 class SingleType(object):
12 """
13 Support for all SSDs, or all HDDS
14 """
15
16 def __init__(self, devices, args):
17 self.args = args
18 self.devices = devices
19 self.hdds = [device for device in devices if device.sys_api['rotational'] == '1']
20 self.ssds = [device for device in devices if device.sys_api['rotational'] == '0']
21 self.computed = {'osds': [], 'vgs': []}
22 self.validate()
23 self.compute()
24
25 def report_json(self):
26 print(json.dumps(self.computed, indent=4, sort_keys=True))
27
28 def report_pretty(self):
29 string = ""
30 string += templates.total_osds.format(
31 total_osds=len(self.hdds) or len(self.ssds) * 2
32 )
33 string += templates.osd_component_titles
34
35 for osd in self.computed['osds']:
36 string += templates.osd_header
37 string += templates.osd_component.format(
38 _type='[data]',
39 path=osd['data']['path'],
40 size=osd['data']['human_readable_size'],
41 percent=osd['data']['percentage'],
42 )
43
44 print(string)
45
46 def validate(self):
47 """
48 Ensure that the minimum requirements for this type of scenario is
49 met, raise an error if the provided devices would not work
50 """
51 # validate minimum size for all devices
52 validators.minimum_device_size(self.devices)
53
54 def compute(self):
55 """
56 Go through the rules needed to properly size the lvs, return
57 a dictionary with the result
58 """
59 osds = self.computed['osds']
60 vgs = self.computed['vgs']
61 for device in self.hdds:
62 vgs.append({'devices': [device.abspath], 'parts': 1})
63 osd = {'data': {}, 'block.db': {}}
64 osd['data']['path'] = device.abspath
65 osd['data']['size'] = device.sys_api['size']
66 osd['data']['parts'] = 1
67 osd['data']['percentage'] = 100
68 osd['data']['human_readable_size'] = str(disk.Size(b=device.sys_api['size']))
69 osds.append(osd)
70
71 for device in self.ssds:
72 # TODO: creates 2 OSDs per device, make this configurable (env var?)
73 extents = lvm.sizing(device.sys_api['size'], parts=2)
74 vgs.append({'devices': [device.abspath], 'parts': 2})
75 for ssd in range(2):
76 osd = {'data': {}, 'block.db': {}}
77 osd['data']['path'] = device.abspath
78 osd['data']['size'] = extents['sizes']
79 osd['data']['parts'] = extents['parts']
80 osd['data']['percentage'] = 50
81 osd['data']['human_readable_size'] = str(disk.Size(b=extents['sizes']))
82 osds.append(osd)
83
84 def execute(self):
85 """
86 Create vgs/lvs from the incoming set of devices, assign their roles
87 (block, block.db, block.wal, etc..) and offload the OSD creation to
88 ``lvm create``
89 """
90 osd_vgs = dict([(osd['data']['path'], None) for osd in self.computed['osds']])
91
92 # create the vgs first, mapping them to the device path
93 for osd in self.computed['osds']:
94 vg = osd_vgs.get(osd['data']['path'])
95 if not vg:
96 vg = lvm.create_vg(osd['data']['path'])
97 osd_vgs[osd['data']['path']] = {'vg': vg, 'parts': osd['data']['parts']}
98
99 # create the lvs from the vgs captured in the beginning
100 for create in osd_vgs.values():
101 lvs = lvm.create_lvs(create['vg'], parts=create['parts'], name_prefix='osd-data')
102 vg_name = create['vg'].name
103 for lv in lvs:
104 command = ['--bluestore', '--data']
105 command.append('%s/%s' % (vg_name, lv.name))
106 if self.args.dmcrypt:
107 command.append('--dmcrypt')
108 if self.args.no_systemd:
109 command.append('--no-systemd')
110 if self.args.crush_device_class:
111 command.extend(['--crush-device-class', self.args.crush_device_class])
112
113 Create(command).main()
114
115
116 class MixedType(object):
117
118 def __init__(self, devices, args):
119 self.args = args
120 self.devices = devices
121 self.hdds = [device for device in devices if device.sys_api['rotational'] == '1']
122 self.ssds = [device for device in devices if device.sys_api['rotational'] == '0']
123 self.computed = {'osds': [], 'vgs': []}
124 self.block_db_size = None
125 # For every HDD we get 1 block.db
126 self.db_lvs = len(self.hdds)
127 self.validate()
128 self.compute()
129
130 def report_json(self):
131 print(json.dumps(self.computed, indent=4, sort_keys=True))
132
133 def report_pretty(self):
134 vg_extents = lvm.sizing(self.total_ssd_size.b, parts=self.db_lvs)
135 db_size = str(disk.Size(b=(vg_extents['sizes'])))
136
137 string = ""
138 string += templates.total_osds.format(
139 total_osds=len(self.hdds)
140 )
141
142 string += templates.ssd_volume_group.format(
143 target='block.db',
144 total_lv_size=str(self.total_ssd_size),
145 total_lvs=vg_extents['parts'],
146 block_lv_size=db_size,
147 block_db_devices=', '.join([ssd.abspath for ssd in self.ssds]),
148 lv_size=str(disk.Size(b=(vg_extents['sizes']))),
149 total_osds=len(self.hdds)
150 )
151
152 string += templates.osd_component_titles
153 for osd in self.computed['osds']:
154 string += templates.osd_header
155 string += templates.osd_component.format(
156 _type='[data]',
157 path=osd['data']['path'],
158 size=osd['data']['human_readable_size'],
159 percent=osd['data']['percentage'])
160
161 string += templates.osd_component.format(
162 _type='[block.db]',
163 path='(volume-group/lv)',
164 size=osd['block.db']['human_readable_size'],
165 percent=osd['block.db']['percentage'])
166
167 print(string)
168
169 def compute(self):
170 osds = self.computed['osds']
171 for device in self.hdds:
172 osd = {'data': {}, 'block.db': {}}
173 osd['data']['path'] = device.abspath
174 osd['data']['size'] = device.sys_api['size']
175 osd['data']['percentage'] = 100
176 osd['data']['human_readable_size'] = str(disk.Size(b=(device.sys_api['size'])))
177 osd['block.db']['path'] = None
178 osd['block.db']['size'] = int(self.block_db_size.b)
179 osd['block.db']['human_readable_size'] = str(self.block_db_size)
180 osd['block.db']['percentage'] = self.vg_extents['percentages']
181 osds.append(osd)
182
183 self.computed['vgs'] = [{
184 'devices': [d.abspath for d in self.ssds],
185 'parts': self.db_lvs,
186 'percentages': self.vg_extents['percentages'],
187 'sizes': self.vg_extents['sizes'],
188 'size': int(self.total_ssd_size.b),
189 'human_readable_sizes': str(disk.Size(b=self.vg_extents['sizes'])),
190 'human_readable_size': str(self.total_ssd_size),
191 }]
192
193 def execute(self):
194 """
195 Create vgs/lvs from the incoming set of devices, assign their roles
196 (block, block.db, block.wal, etc..) and offload the OSD creation to
197 ``lvm create``
198 """
199 # create the single vg for all block.db lv's first
200 vg_info = self.computed['vgs'][0]
201 vg = lvm.create_vg(vg_info['devices'])
202
203 # now produce all the block.db lvs needed from that single vg
204 db_lvs = lvm.create_lvs(vg, parts=vg_info['parts'], name_prefix='osd-block-db')
205
206 # create the data lvs, and create the OSD with the matching block.db lvs from before
207 for osd in self.computed['osds']:
208 vg = lvm.create_vg(osd['data']['path'])
209 data_lv = lvm.create_lv('osd-data-%s' % str(uuid4()), vg.name)
210 db_lv = db_lvs.pop()
211 command = [
212 '--bluestore',
213 '--data', "%s/%s" % (data_lv.vg_name, data_lv.name),
214 '--block.db', '%s/%s' % (db_lv.vg_name, db_lv.name)
215 ]
216 if self.args.dmcrypt:
217 command.append('--dmcrypt')
218 if self.args.no_systemd:
219 command.append('--no-systemd')
220 if self.args.crush_device_class:
221 command.extend(['--crush-device-class', self.args.crush_device_class])
222
223 Create(command).main()
224
225 def validate(self):
226 """
227 HDDs represent data devices, and solid state devices are for block.db,
228 make sure that the number of data devices would have enough LVs and
229 those LVs would be large enough to accommodate a block.db
230 """
231 # validate minimum size for all devices
232 validators.minimum_device_size(self.devices)
233
234 # add all the size available in solid drives and divide it by the
235 # expected number of osds, the expected output should be larger than
236 # the minimum alllowed for block.db
237 self.total_ssd_size = disk.Size(b=0)
238 for ssd in self.ssds:
239 self.total_ssd_size += disk.Size(b=ssd.sys_api['size'])
240
241 self.block_db_size = self.total_ssd_size / self.db_lvs
242 self.vg_extents = lvm.sizing(self.total_ssd_size.b, parts=self.db_lvs)
243
244 # min 2GB of block.db is allowed
245 msg = 'Total solid size (%s) is not enough for block.db LVs larger than 2 GB'
246 if self.block_db_size < disk.Size(gb=2):
247 # use ad-hoc exception here
248 raise RuntimeError(msg % self.total_ssd_size)