Skip to content

Commit ef4e55b

Browse files
authored
Merge pull request ceph#61848 from guits/split-db-block-collocated
ceph-volume: support splitting db even on collocated scenario
2 parents 3dd4851 + 55c3ac5 commit ef4e55b

27 files changed

+237
-121
lines changed

src/ceph-volume/ceph_volume/devices/lvm/batch.py

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
* {path: <25} {size: <10} {state}"""
2020

2121

22-
def ensure_disjoint_device_lists(data: List[str],
23-
db: Optional[List[str]] = None,
24-
wal: Optional[List[str]] = None) -> None:
22+
def ensure_disjoint_device_lists(data: List[device.Device],
23+
db: Optional[List[device.Device]] = None,
24+
wal: Optional[List[device.Device]] = None) -> None:
2525
if db is None:
2626
db = []
2727
if wal is None:
@@ -341,6 +341,10 @@ def main(self) -> None:
341341
self.parser.print_help()
342342
raise SystemExit(0)
343343

344+
self.args.has_block_db_size_without_db_devices = (
345+
self.args.block_db_size is not None and not self.args.db_devices
346+
)
347+
344348
if (self.args.auto and not self.args.db_devices and not
345349
self.args.wal_devices):
346350
self._sort_rotational_disks()
@@ -393,7 +397,10 @@ def get_deployment_layout(self) -> List["OSD"]:
393397
functions.
394398
'''
395399
devices = self.args.devices
396-
fast_devices = self.args.db_devices
400+
if self.args.block_db_size is not None:
401+
fast_devices = self.args.db_devices or self.args.devices
402+
else:
403+
fast_devices = self.args.db_devices
397404
very_fast_devices = self.args.wal_devices
398405
plan = []
399406
phys_devs, lvm_devs = separate_devices_from_lvs(devices)
@@ -436,10 +443,20 @@ def get_deployment_layout(self) -> List["OSD"]:
436443
len(very_fast_allocations), num_osds))
437444
exit(1)
438445

439-
for osd in plan:
440-
if fast_devices:
441-
osd.add_fast_device(*fast_allocations.pop(),
442-
type_=fast_type)
446+
if fast_devices:
447+
fast_alloc: Optional[tuple[str, float, disk.Size, int]] = None
448+
for osd in plan:
449+
if self.args.has_block_db_size_without_db_devices:
450+
for i, _fast_alloc in enumerate(fast_allocations):
451+
if osd.data.path == _fast_alloc[0]:
452+
fast_alloc = fast_allocations.pop(i)
453+
break
454+
else:
455+
fast_alloc = fast_allocations.pop() if fast_allocations else None
456+
457+
if fast_alloc:
458+
osd.add_fast_device(*fast_alloc, type_=fast_type)
459+
443460
if very_fast_devices and self.args.objectstore == 'bluestore':
444461
osd.add_very_fast_device(*very_fast_allocations.pop())
445462
return plan
@@ -580,34 +597,48 @@ def report_json(self) -> Dict[str, Any]:
580597
return {k: str(v) for k, v in self._get_osd_plan().items()}
581598

582599
def get_physical_osds(devices: List[device.Device], args: argparse.Namespace) -> List[Batch.OSD]:
583-
'''
584-
Goes through passed physical devices and assigns OSDs
585-
'''
586-
data_slots = args.osds_per_device
587-
if args.data_slots:
588-
data_slots = max(args.data_slots, args.osds_per_device)
589-
rel_data_size = args.data_allocate_fraction / data_slots
590-
mlogger.debug('relative data size: {}'.format(rel_data_size))
600+
"""
601+
Goes through passed physical devices and assigns OSDs.
602+
"""
603+
data_slots = max(args.data_slots, args.osds_per_device) if args.data_slots else args.osds_per_device
591604
ret = []
605+
592606
for dev in devices:
593-
if dev.available_lvm:
594-
dev_size = dev.vg_size[0]
595-
abs_size = disk.Size(b=int(dev_size * rel_data_size))
596-
free_size = dev.vg_free[0]
597-
for _ in range(args.osds_per_device):
598-
if abs_size > free_size:
599-
break
600-
free_size -= abs_size.b
601-
osd_id = None
602-
if args.osd_ids:
603-
osd_id = args.osd_ids.pop()
604-
ret.append(Batch.OSD(dev.path,
605-
rel_data_size,
606-
abs_size,
607-
args.osds_per_device,
608-
osd_id,
609-
'dmcrypt' if args.dmcrypt else None,
610-
dev.symlink))
607+
if not dev.available_lvm:
608+
continue
609+
610+
total_dev_size = dev.vg_size[0]
611+
dev_size = total_dev_size
612+
rel_data_size = args.data_allocate_fraction / data_slots
613+
614+
if args.has_block_db_size_without_db_devices:
615+
all_db_space = args.block_db_size * data_slots
616+
dev_size -= all_db_space.b.as_int()
617+
618+
abs_size = disk.Size(b=int(dev_size * rel_data_size))
619+
620+
if args.has_block_db_size_without_db_devices:
621+
rel_data_size = abs_size / disk.Size(b=total_dev_size)
622+
623+
free_size = dev.vg_free[0]
624+
625+
for _ in range(args.osds_per_device):
626+
if abs_size.b > free_size:
627+
break
628+
629+
free_size -= abs_size.b
630+
osd_id = args.osd_ids.pop() if args.osd_ids else None
631+
632+
ret.append(Batch.OSD(
633+
dev.path,
634+
rel_data_size,
635+
abs_size,
636+
args.osds_per_device,
637+
osd_id,
638+
'dmcrypt' if args.dmcrypt else None,
639+
dev.symlink
640+
))
641+
611642
return ret
612643

613644
def get_lvm_osds(lvs: List[device.Device], args: argparse.Namespace) -> List[Batch.OSD]:

src/ceph-volume/ceph_volume/tests/api/test_lvm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import pytest
3-
from mock.mock import patch
3+
from unittest.mock import patch
44
from ceph_volume import process, exceptions
55
from ceph_volume.api import lvm as api
66

src/ceph-volume/ceph_volume/tests/conftest.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import pytest
3-
from mock.mock import patch, PropertyMock, create_autospec, Mock
3+
import argparse
4+
from unittest.mock import patch, PropertyMock, create_autospec, Mock, MagicMock
45
from ceph_volume.api import lvm
56
from ceph_volume.util import disk
67
from ceph_volume.util import device
@@ -29,14 +30,14 @@ def __call__(self, *a, **kw):
2930

3031
class Factory(object):
3132

32-
def __init__(self, **kw):
33+
def __init__(self, **kw: Any) -> None:
3334
for k, v in kw.items():
3435
setattr(self, k, v)
3536

3637

3738
@pytest.fixture
38-
def factory():
39-
return Factory
39+
def factory() -> Callable[..., argparse.Namespace]:
40+
return argparse.Namespace
4041

4142
def objectstore_bluestore_factory(**kw):
4243
o = objectstore.bluestore.BlueStore([])
@@ -70,29 +71,29 @@ def mock_lv():
7071
return dev
7172
return mock_lv
7273

73-
def mock_device(name='foo',
74-
vg_name='vg_foo',
75-
vg_size=None,
76-
lv_name='lv_foo',
77-
lv_size=None,
78-
path='foo',
79-
lv_path='',
80-
number_lvs=0):
74+
def mock_device(**kw: Any) -> MagicMock:
75+
number_lvs = kw.get('number_lvs', 0)
76+
default_values = {
77+
'vg_size': [21474836480],
78+
'lv_size': kw.get('vg_size', [21474836480]),
79+
'path': f"/dev/{kw.get('path', 'foo')}",
80+
'vg_name': 'vg_foo',
81+
'lv_name': 'lv_foo',
82+
'symlink': None,
83+
'available_lvm': True,
84+
'vg_free': kw.get('vg_size', [21474836480]),
85+
'lvs': [],
86+
'lv_path': f"/dev/{kw.get('vg_name', 'vg_foo')}/{kw.get('lv_name', 'lv_foo')}",
87+
'vgs': [lvm.VolumeGroup(vg_name=kw.get('vg_name', 'vg_foo'), lv_name=kw.get('lv_name', 'lv_foo'))],
88+
}
89+
for key, value in default_values.items():
90+
kw.setdefault(key, value)
91+
8192
dev = create_autospec(device.Device)
82-
if vg_size is None:
83-
dev.vg_size = [21474836480]
84-
if lv_size is None:
85-
lv_size = dev.vg_size
86-
dev.lv_size = lv_size
87-
dev.path = f'/dev/{path}'
88-
dev.vg_name = f'{vg_name}'
89-
dev.lv_name = f'{lv_name}'
90-
dev.lv_path = lv_path if lv_path else f'/dev/{dev.vg_name}/{dev.lv_name}'
91-
dev.symlink = None
92-
dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)]
93-
dev.available_lvm = True
94-
dev.vg_free = dev.vg_size
95-
dev.lvs = []
93+
94+
for k, v in kw.items():
95+
dev.__dict__[k] = v
96+
9697
for n in range(0, number_lvs):
9798
dev.lvs.append(lvm.Volume(vg_name=f'{dev.vg_name}{n}',
9899
lv_name=f'{dev.lv_name}-{n}',

src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ceph_volume.tests.conftest import Capture
66
from ceph_volume import objectstore
77
#from ceph_volume.util.prepare import create_key
8-
from mock import patch, call
8+
from unittest.mock import patch, call
99
from argparse import Namespace
1010

1111
class Args(object):

src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
import json
33
import random
44

5-
from argparse import ArgumentError
6-
from mock import MagicMock, patch
5+
from argparse import ArgumentError, Namespace
6+
from unittest.mock import MagicMock, patch
77

88
from ceph_volume.devices.lvm import batch
9-
from ceph_volume.util import arg_validators
9+
from ceph_volume.util import arg_validators, disk, device
10+
from ceph_volume.configuration import Conf
11+
from typing import List, Callable
1012

1113

1214
class TestBatch(object):
@@ -20,9 +22,9 @@ def test_invalid_osd_ids_passed(self):
2022
with pytest.raises(SystemExit):
2123
batch.Batch(argv=['--osd-ids', '1', 'foo']).main()
2224

23-
def test_disjoint_device_lists(self, factory):
24-
device1 = factory(used_by_ceph=False, available=True, abspath="/dev/sda")
25-
device2 = factory(used_by_ceph=False, available=True, abspath="/dev/sdb")
25+
def test_disjoint_device_lists(self, mock_device_generator: Callable) -> None:
26+
device1 = mock_device_generator(used_by_ceph=False, available=True, abspath='/dev/sda')
27+
device2 = mock_device_generator(used_by_ceph=False, available=True, abspath='/dev/sdb')
2628
devices = [device1, device2]
2729
db_devices = [device2]
2830
with pytest.raises(Exception) as disjoint_ex:
@@ -55,7 +57,8 @@ def test_report(self, format_, factory, conf_ceph_stub, mock_device_generator):
5557
db_devices=[],
5658
wal_devices=[],
5759
objectstore='bluestore',
58-
block_db_size="1G",
60+
block_db_size=disk.Size(gb=1),
61+
block_db_slots=1,
5962
dmcrypt=True,
6063
data_allocate_fraction=1.0,
6164
)
@@ -174,38 +177,53 @@ def test_batch_sort_mixed(self, factory, objectstore):
174177
assert len(b.args.devices) == 2
175178
assert len(b.args.db_devices) == 1
176179

177-
def test_get_physical_osds_return_len(self, factory,
178-
mock_devices_available,
179-
conf_ceph_stub,
180-
osds_per_device):
180+
def test_get_physical_osds_return_len(self,
181+
factory: Callable[..., Namespace],
182+
mock_devices_available: List[device.Device],
183+
conf_ceph_stub: Callable[[str], Conf],
184+
osds_per_device: int) -> None:
181185
conf_ceph_stub('[global]\nfsid=asdf-lkjh')
182-
args = factory(data_slots=1, osds_per_device=osds_per_device,
183-
osd_ids=[], dmcrypt=False,
184-
data_allocate_fraction=1.0)
186+
args = factory(data_slots=1,
187+
osds_per_device=osds_per_device,
188+
osd_ids=[],
189+
dmcrypt=False,
190+
data_allocate_fraction=1.0,
191+
block_db_size=None,
192+
db_devices=[])
185193
osds = batch.get_physical_osds(mock_devices_available, args)
186194
assert len(osds) == len(mock_devices_available) * osds_per_device
187195

188-
def test_get_physical_osds_rel_size(self, factory,
189-
mock_devices_available,
190-
conf_ceph_stub,
191-
osds_per_device,
192-
data_allocate_fraction):
193-
args = factory(data_slots=1, osds_per_device=osds_per_device,
194-
osd_ids=[], dmcrypt=False,
195-
data_allocate_fraction=data_allocate_fraction)
196+
def test_get_physical_osds_rel_size(self,
197+
factory: Callable[..., Namespace],
198+
mock_devices_available: List[device.Device],
199+
conf_ceph_stub: Callable[[str], Conf],
200+
osds_per_device: int,
201+
data_allocate_fraction: float) -> None:
202+
args = factory(data_slots=1,
203+
osds_per_device=osds_per_device,
204+
osd_ids=[],
205+
dmcrypt=False,
206+
data_allocate_fraction=data_allocate_fraction,
207+
block_db_size=None,
208+
db_devices=[])
196209
osds = batch.get_physical_osds(mock_devices_available, args)
197210
for osd in osds:
198211
assert osd.data[1] == data_allocate_fraction / osds_per_device
199212

200-
def test_get_physical_osds_abs_size(self, factory,
201-
mock_devices_available,
202-
conf_ceph_stub,
203-
osds_per_device,
204-
data_allocate_fraction):
213+
def test_get_physical_osds_abs_size(self,
214+
factory: Callable[..., Namespace],
215+
mock_devices_available: List[device.Device],
216+
conf_ceph_stub: Callable[[str], Conf],
217+
osds_per_device: int,
218+
data_allocate_fraction: float) -> None:
205219
conf_ceph_stub('[global]\nfsid=asdf-lkjh')
206-
args = factory(data_slots=1, osds_per_device=osds_per_device,
207-
osd_ids=[], dmcrypt=False,
208-
data_allocate_fraction=data_allocate_fraction)
220+
args = factory(data_slots=1,
221+
osds_per_device=osds_per_device,
222+
osd_ids=[],
223+
dmcrypt=False,
224+
data_allocate_fraction=data_allocate_fraction,
225+
block_db_size=None,
226+
db_devices=[])
209227
osds = batch.get_physical_osds(mock_devices_available, args)
210228
for osd, dev in zip(osds, mock_devices_available):
211229
assert osd.data[2] == int(dev.vg_size[0] * (data_allocate_fraction / osds_per_device))

src/ceph-volume/ceph_volume/tests/devices/lvm/test_deactivate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from mock.mock import patch
2+
from unittest.mock import patch
33
from ceph_volume.api import lvm
44
from ceph_volume.devices.lvm import deactivate
55

src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from ceph_volume.devices import lvm
33
from ceph_volume.api import lvm as api
4-
from mock import patch, Mock
4+
from unittest.mock import patch, Mock
55

66
# TODO: add tests for following commands -
77
# ceph-volume list

src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from mock.mock import patch, Mock
2+
from unittest.mock import patch, Mock
33
from ceph_volume import process
44
from ceph_volume.api import lvm as api
55
from ceph_volume.devices.lvm import migrate

src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from ceph_volume.devices import lvm
33
from ceph_volume.api import lvm as api
4-
from mock.mock import patch
4+
from unittest.mock import patch
55
from ceph_volume import objectstore
66

77

src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import pytest
44
from copy import deepcopy
5-
from mock.mock import patch, call, Mock
5+
from unittest.mock import patch, call, Mock
66
from ceph_volume import process
77
from ceph_volume.api import lvm as api
88
from ceph_volume.devices.lvm import zap

0 commit comments

Comments
 (0)