]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py
import ceph 16.2.7
[ceph.git] / ceph / src / ceph-volume / ceph_volume / tests / devices / lvm / test_batch.py
1 import pytest
2 import json
3 import random
4
5 from argparse import ArgumentError
6 from mock import MagicMock, patch
7
8 from ceph_volume.devices.lvm import batch
9 from ceph_volume.util import arg_validators
10
11
12 class TestBatch(object):
13
14 def test_batch_instance(self, is_root):
15 b = batch.Batch([])
16 b.main()
17
18 def test_invalid_osd_ids_passed(self):
19 with pytest.raises(SystemExit):
20 batch.Batch(argv=['--osd-ids', '1', 'foo']).main()
21
22 def test_disjoint_device_lists(self, factory):
23 device1 = factory(used_by_ceph=False, available=True, abspath="/dev/sda")
24 device2 = factory(used_by_ceph=False, available=True, abspath="/dev/sdb")
25 devices = [device1, device2]
26 db_devices = [device2]
27 with pytest.raises(Exception) as disjoint_ex:
28 batch.ensure_disjoint_device_lists(devices, db_devices)
29 assert 'Device lists are not disjoint' in str(disjoint_ex.value)
30
31 @patch('ceph_volume.util.arg_validators.Device')
32 def test_reject_partition(self, mocked_device):
33 mocked_device.return_value = MagicMock(
34 is_partition=True,
35 has_gpt_headers=False,
36 )
37 with pytest.raises(ArgumentError):
38 arg_validators.ValidBatchDevice()('foo')
39
40 @pytest.mark.parametrize('format_', ['pretty', 'json', 'json-pretty'])
41 def test_report(self, format_, factory, conf_ceph_stub, mock_device_generator):
42 # just ensure reporting works
43 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
44 devs = [mock_device_generator() for _ in range(5)]
45 args = factory(data_slots=1,
46 osds_per_device=1,
47 osd_ids=[],
48 report=True,
49 format=format_,
50 devices=devs,
51 db_devices=[],
52 wal_devices=[],
53 bluestore=True,
54 block_db_size="1G",
55 dmcrypt=True,
56 )
57 b = batch.Batch([])
58 plan = b.get_plan(args)
59 b.args = args
60 b.report(plan)
61
62 @pytest.mark.parametrize('format_', ['json', 'json-pretty'])
63 def test_json_report_valid_empty(self, format_, factory, conf_ceph_stub, mock_device_generator):
64 # ensure json reports are valid when empty
65 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
66 devs = []
67 args = factory(data_slots=1,
68 osds_per_device=1,
69 osd_ids=[],
70 report=True,
71 format=format_,
72 devices=devs,
73 db_devices=[],
74 wal_devices=[],
75 bluestore=True,
76 block_db_size="1G",
77 dmcrypt=True,
78 )
79 b = batch.Batch([])
80 plan = b.get_plan(args)
81 b.args = args
82 report = b._create_report(plan)
83 json.loads(report)
84
85 @pytest.mark.parametrize('format_', ['json', 'json-pretty'])
86 def test_json_report_valid_empty_unavailable_fast(self, format_, factory, conf_ceph_stub, mock_device_generator):
87 # ensure json reports are valid when empty
88 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
89 devs = [mock_device_generator() for _ in range(5)]
90 fast_devs = [mock_device_generator()]
91 fast_devs[0].available_lvm = False
92 args = factory(data_slots=1,
93 osds_per_device=1,
94 osd_ids=[],
95 report=True,
96 format=format_,
97 devices=devs,
98 db_devices=fast_devs,
99 wal_devices=[],
100 bluestore=True,
101 block_db_size="1G",
102 dmcrypt=True,
103 )
104 b = batch.Batch([])
105 plan = b.get_plan(args)
106 b.args = args
107 report = b._create_report(plan)
108 json.loads(report)
109
110
111 @pytest.mark.parametrize('format_', ['json', 'json-pretty'])
112 def test_json_report_valid_empty_unavailable_very_fast(self, format_, factory, conf_ceph_stub, mock_device_generator):
113 # ensure json reports are valid when empty
114 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
115 devs = [mock_device_generator() for _ in range(5)]
116 fast_devs = [mock_device_generator()]
117 very_fast_devs = [mock_device_generator()]
118 very_fast_devs[0].available_lvm = False
119 args = factory(data_slots=1,
120 osds_per_device=1,
121 osd_ids=[],
122 report=True,
123 format=format_,
124 devices=devs,
125 db_devices=fast_devs,
126 wal_devices=very_fast_devs,
127 bluestore=True,
128 block_db_size="1G",
129 dmcrypt=True,
130 )
131 b = batch.Batch([])
132 plan = b.get_plan(args)
133 b.args = args
134 report = b._create_report(plan)
135 json.loads(report)
136
137 @pytest.mark.parametrize('rota', [0, 1])
138 def test_batch_sort_full(self, factory, rota):
139 device1 = factory(used_by_ceph=False, available=True, rotational=rota, abspath="/dev/sda")
140 device2 = factory(used_by_ceph=False, available=True, rotational=rota, abspath="/dev/sdb")
141 device3 = factory(used_by_ceph=False, available=True, rotational=rota, abspath="/dev/sdc")
142 devices = [device1, device2, device3]
143 args = factory(report=True,
144 devices=devices,
145 filestore=False,
146 )
147 b = batch.Batch([])
148 b.args = args
149 b._sort_rotational_disks()
150 assert len(b.args.devices) == 3
151
152 @pytest.mark.parametrize('objectstore', ['bluestore', 'filestore'])
153 def test_batch_sort_mixed(self, factory, objectstore):
154 device1 = factory(used_by_ceph=False, available=True, rotational=1, abspath="/dev/sda")
155 device2 = factory(used_by_ceph=False, available=True, rotational=1, abspath="/dev/sdb")
156 device3 = factory(used_by_ceph=False, available=True, rotational=0, abspath="/dev/sdc")
157 devices = [device1, device2, device3]
158 args = factory(report=True,
159 devices=devices,
160 filestore=False if objectstore == 'bluestore' else True,
161 )
162 b = batch.Batch([])
163 b.args = args
164 b._sort_rotational_disks()
165 assert len(b.args.devices) == 2
166 if objectstore == 'bluestore':
167 assert len(b.args.db_devices) == 1
168 else:
169 assert len(b.args.journal_devices) == 1
170
171 def test_get_physical_osds_return_len(self, factory,
172 mock_devices_available,
173 conf_ceph_stub,
174 osds_per_device):
175 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
176 args = factory(data_slots=1, osds_per_device=osds_per_device,
177 osd_ids=[], dmcrypt=False)
178 osds = batch.get_physical_osds(mock_devices_available, args)
179 assert len(osds) == len(mock_devices_available) * osds_per_device
180
181 def test_get_physical_osds_rel_size(self, factory,
182 mock_devices_available,
183 conf_ceph_stub,
184 osds_per_device):
185 args = factory(data_slots=1, osds_per_device=osds_per_device,
186 osd_ids=[], dmcrypt=False)
187 osds = batch.get_physical_osds(mock_devices_available, args)
188 for osd in osds:
189 assert osd.data[1] == 1.0 / osds_per_device
190
191 def test_get_physical_osds_abs_size(self, factory,
192 mock_devices_available,
193 conf_ceph_stub,
194 osds_per_device):
195 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
196 args = factory(data_slots=1, osds_per_device=osds_per_device,
197 osd_ids=[], dmcrypt=False)
198 osds = batch.get_physical_osds(mock_devices_available, args)
199 for osd, dev in zip(osds, mock_devices_available):
200 assert osd.data[2] == int(dev.vg_size[0] / osds_per_device)
201
202 def test_get_physical_osds_osd_ids(self, factory,
203 mock_devices_available,
204 osds_per_device):
205 pass
206
207 def test_get_physical_fast_allocs_length(self, factory,
208 conf_ceph_stub,
209 mock_devices_available):
210 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
211 args = factory(block_db_slots=None, get_block_db_size=None)
212 fast = batch.get_physical_fast_allocs(mock_devices_available,
213 'block_db', 2, 2, args)
214 assert len(fast) == 2
215
216 def test_batch_fast_allocations_one_block_db_length(self, factory, conf_ceph_stub,
217 mock_lv_device_generator):
218 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
219
220 b = batch.Batch([])
221 db_lv_devices = [mock_lv_device_generator()]
222 fast = b.fast_allocations(db_lv_devices, 1, 0, 'block_db')
223 assert len(fast) == 1
224
225 @pytest.mark.parametrize('occupied_prior', range(7))
226 @pytest.mark.parametrize('slots,num_devs',
227 [l for sub in [list(zip([x]*x, range(1, x + 1))) for x in range(1,7)] for l in sub])
228 def test_get_physical_fast_allocs_length_existing(self,
229 num_devs,
230 slots,
231 occupied_prior,
232 factory,
233 conf_ceph_stub,
234 mock_device_generator):
235 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
236 occupied_prior = min(occupied_prior, slots)
237 devs = [mock_device_generator() for _ in range(num_devs)]
238 already_assigned = 0
239 while already_assigned < occupied_prior:
240 dev_i = random.randint(0, num_devs - 1)
241 dev = devs[dev_i]
242 if len(dev.lvs) < occupied_prior:
243 dev.lvs.append('foo')
244 dev.path = '/dev/bar'
245 already_assigned = sum([len(d.lvs) for d in devs])
246 args = factory(block_db_slots=None, get_block_db_size=None)
247 expected_num_osds = max(len(devs) * slots - occupied_prior, 0)
248 fast = batch.get_physical_fast_allocs(devs,
249 'block_db', slots,
250 expected_num_osds, args)
251 assert len(fast) == expected_num_osds
252 expected_assignment_on_used_devices = sum([slots - len(d.lvs) for d in devs if len(d.lvs) > 0])
253 assert len([f for f in fast if f[0] == '/dev/bar']) == expected_assignment_on_used_devices
254 assert len([f for f in fast if f[0] != '/dev/bar']) == expected_num_osds - expected_assignment_on_used_devices
255
256 def test_get_lvm_osds_return_len(self, factory,
257 mock_lv_device_generator,
258 conf_ceph_stub,
259 osds_per_device):
260 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
261 args = factory(data_slots=1, osds_per_device=osds_per_device,
262 osd_ids=[], dmcrypt=False)
263 mock_lvs = [mock_lv_device_generator()]
264 osds = batch.get_lvm_osds(mock_lvs, args)
265 assert len(osds) == 1
266
267
268 class TestBatchOsd(object):
269
270 def test_osd_class_ctor(self):
271 osd = batch.Batch.OSD('/dev/data', 1, '5G', 1, 1, None)
272 assert osd.data == batch.Batch.OSD.VolSpec('/dev/data',
273 1,
274 '5G',
275 1,
276 'data')
277 def test_add_fast(self):
278 osd = batch.Batch.OSD('/dev/data', 1, '5G', 1, 1, None)
279 osd.add_fast_device('/dev/db', 1, '5G', 1, 'block_db')
280 assert osd.fast == batch.Batch.OSD.VolSpec('/dev/db',
281 1,
282 '5G',
283 1,
284 'block_db')
285
286 def test_add_very_fast(self):
287 osd = batch.Batch.OSD('/dev/data', 1, '5G', 1, 1, None)
288 osd.add_very_fast_device('/dev/wal', 1, '5G', 1)
289 assert osd.very_fast == batch.Batch.OSD.VolSpec('/dev/wal',
290 1,
291 '5G',
292 1,
293 'block_wal')