5 from argparse
import ArgumentError
6 from mock
import MagicMock
, patch
8 from ceph_volume
.devices
.lvm
import batch
9 from ceph_volume
.util
import arg_validators
12 class TestBatch(object):
14 def test_batch_instance(self
, is_root
):
18 def test_invalid_osd_ids_passed(self
):
19 with pytest
.raises(SystemExit):
20 batch
.Batch(argv
=['--osd-ids', '1', 'foo']).main()
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
)
31 @patch('ceph_volume.util.arg_validators.Device')
32 def test_reject_partition(self
, mocked_device
):
33 mocked_device
.return_value
= MagicMock(
37 has_gpt_headers
=False,
40 with pytest
.raises(ArgumentError
):
41 arg_validators
.ValidBatchDevice()('foo')
43 @pytest.mark
.parametrize('format_', ['pretty', 'json', 'json-pretty'])
44 def test_report(self
, format_
, factory
, conf_ceph_stub
, mock_device_generator
):
45 # just ensure reporting works
46 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
47 devs
= [mock_device_generator() for _
in range(5)]
48 args
= factory(data_slots
=1,
59 data_allocate_fraction
=1.0,
62 plan
= b
.get_plan(args
)
66 @pytest.mark
.parametrize('format_', ['json', 'json-pretty'])
67 def test_json_report_valid_empty(self
, format_
, factory
, conf_ceph_stub
, mock_device_generator
):
68 # ensure json reports are valid when empty
69 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
71 args
= factory(data_slots
=1,
82 data_allocate_fraction
=1.0,
85 plan
= b
.get_plan(args
)
87 report
= b
._create
_report
(plan
)
90 @pytest.mark
.parametrize('format_', ['json', 'json-pretty'])
91 def test_json_report_valid_empty_unavailable_fast(self
, format_
, factory
, conf_ceph_stub
, mock_device_generator
):
92 # ensure json reports are valid when empty
93 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
94 devs
= [mock_device_generator() for _
in range(5)]
95 fast_devs
= [mock_device_generator()]
96 fast_devs
[0].available_lvm
= False
97 args
= factory(data_slots
=1,
103 db_devices
=fast_devs
,
108 data_allocate_fraction
=1.0,
111 plan
= b
.get_plan(args
)
113 report
= b
._create
_report
(plan
)
117 @pytest.mark
.parametrize('format_', ['json', 'json-pretty'])
118 def test_json_report_valid_empty_unavailable_very_fast(self
, format_
, factory
, conf_ceph_stub
, mock_device_generator
):
119 # ensure json reports are valid when empty
120 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
121 devs
= [mock_device_generator() for _
in range(5)]
122 fast_devs
= [mock_device_generator()]
123 very_fast_devs
= [mock_device_generator()]
124 very_fast_devs
[0].available_lvm
= False
125 args
= factory(data_slots
=1,
131 db_devices
=fast_devs
,
132 wal_devices
=very_fast_devs
,
136 data_allocate_fraction
=1.0,
139 plan
= b
.get_plan(args
)
141 report
= b
._create
_report
(plan
)
144 @pytest.mark
.parametrize('rota', [0, 1])
145 def test_batch_sort_full(self
, factory
, rota
):
146 device1
= factory(used_by_ceph
=False, available
=True, rotational
=rota
, abspath
="/dev/sda")
147 device2
= factory(used_by_ceph
=False, available
=True, rotational
=rota
, abspath
="/dev/sdb")
148 device3
= factory(used_by_ceph
=False, available
=True, rotational
=rota
, abspath
="/dev/sdc")
149 devices
= [device1
, device2
, device3
]
150 args
= factory(report
=True,
156 b
._sort
_rotational
_disks
()
157 assert len(b
.args
.devices
) == 3
159 @pytest.mark
.parametrize('objectstore', ['bluestore', 'filestore'])
160 def test_batch_sort_mixed(self
, factory
, objectstore
):
161 device1
= factory(used_by_ceph
=False, available
=True, rotational
=1, abspath
="/dev/sda")
162 device2
= factory(used_by_ceph
=False, available
=True, rotational
=1, abspath
="/dev/sdb")
163 device3
= factory(used_by_ceph
=False, available
=True, rotational
=0, abspath
="/dev/sdc")
164 devices
= [device1
, device2
, device3
]
165 args
= factory(report
=True,
167 filestore
=False if objectstore
== 'bluestore' else True,
171 b
._sort
_rotational
_disks
()
172 assert len(b
.args
.devices
) == 2
173 if objectstore
== 'bluestore':
174 assert len(b
.args
.db_devices
) == 1
176 assert len(b
.args
.journal_devices
) == 1
178 def test_get_physical_osds_return_len(self
, factory
,
179 mock_devices_available
,
182 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
183 args
= factory(data_slots
=1, osds_per_device
=osds_per_device
,
184 osd_ids
=[], dmcrypt
=False,
185 data_allocate_fraction
=1.0)
186 osds
= batch
.get_physical_osds(mock_devices_available
, args
)
187 assert len(osds
) == len(mock_devices_available
) * osds_per_device
189 def test_get_physical_osds_rel_size(self
, factory
,
190 mock_devices_available
,
193 data_allocate_fraction
):
194 args
= factory(data_slots
=1, osds_per_device
=osds_per_device
,
195 osd_ids
=[], dmcrypt
=False,
196 data_allocate_fraction
=data_allocate_fraction
)
197 osds
= batch
.get_physical_osds(mock_devices_available
, args
)
199 assert osd
.data
[1] == data_allocate_fraction
/ osds_per_device
201 def test_get_physical_osds_abs_size(self
, factory
,
202 mock_devices_available
,
205 data_allocate_fraction
):
206 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
207 args
= factory(data_slots
=1, osds_per_device
=osds_per_device
,
208 osd_ids
=[], dmcrypt
=False,
209 data_allocate_fraction
=data_allocate_fraction
)
210 osds
= batch
.get_physical_osds(mock_devices_available
, args
)
211 for osd
, dev
in zip(osds
, mock_devices_available
):
212 assert osd
.data
[2] == int(dev
.vg_size
[0] * (data_allocate_fraction
/ osds_per_device
))
214 def test_get_physical_osds_osd_ids(self
, factory
,
215 mock_devices_available
,
219 def test_get_physical_fast_allocs_length(self
, factory
,
221 mock_devices_available
):
222 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
223 args
= factory(block_db_slots
=None, get_block_db_size
=None)
224 fast
= batch
.get_physical_fast_allocs(mock_devices_available
,
225 'block_db', 2, 2, args
)
226 assert len(fast
) == 2
228 def test_batch_fast_allocations_one_block_db_length(self
, factory
, conf_ceph_stub
,
229 mock_lv_device_generator
):
230 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
233 db_lv_devices
= [mock_lv_device_generator()]
234 fast
= b
.fast_allocations(db_lv_devices
, 1, 0, 'block_db')
235 assert len(fast
) == 1
237 @pytest.mark
.parametrize('occupied_prior', range(7))
238 @pytest.mark
.parametrize('slots,num_devs',
239 [l
for sub
in [list(zip([x
]*x
, range(1, x
+ 1))) for x
in range(1,7)] for l
in sub
])
240 def test_get_physical_fast_allocs_length_existing(self
,
246 mock_device_generator
):
247 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
248 occupied_prior
= min(occupied_prior
, slots
)
249 devs
= [mock_device_generator() for _
in range(num_devs
)]
251 while already_assigned
< occupied_prior
:
252 dev_i
= random
.randint(0, num_devs
- 1)
254 if len(dev
.lvs
) < occupied_prior
:
255 dev
.lvs
.append('foo')
256 dev
.path
= '/dev/bar'
257 already_assigned
= sum([len(d
.lvs
) for d
in devs
])
258 args
= factory(block_db_slots
=None, get_block_db_size
=None)
259 expected_num_osds
= max(len(devs
) * slots
- occupied_prior
, 0)
260 fast
= batch
.get_physical_fast_allocs(devs
,
262 expected_num_osds
, args
)
263 assert len(fast
) == expected_num_osds
264 expected_assignment_on_used_devices
= sum([slots
- len(d
.lvs
) for d
in devs
if len(d
.lvs
) > 0])
265 assert len([f
for f
in fast
if f
[0] == '/dev/bar']) == expected_assignment_on_used_devices
266 assert len([f
for f
in fast
if f
[0] != '/dev/bar']) == expected_num_osds
- expected_assignment_on_used_devices
268 def test_get_lvm_osds_return_len(self
, factory
,
269 mock_lv_device_generator
,
272 conf_ceph_stub('[global]\nfsid=asdf-lkjh')
273 args
= factory(data_slots
=1, osds_per_device
=osds_per_device
,
274 osd_ids
=[], dmcrypt
=False)
275 mock_lvs
= [mock_lv_device_generator()]
276 osds
= batch
.get_lvm_osds(mock_lvs
, args
)
277 assert len(osds
) == 1
280 class TestBatchOsd(object):
282 def test_osd_class_ctor(self
):
283 osd
= batch
.Batch
.OSD('/dev/data', 1, '5G', 1, 1, None)
284 assert osd
.data
== batch
.Batch
.OSD
.VolSpec('/dev/data',
289 def test_add_fast(self
):
290 osd
= batch
.Batch
.OSD('/dev/data', 1, '5G', 1, 1, None)
291 osd
.add_fast_device('/dev/db', 1, '5G', 1, 'block_db')
292 assert osd
.fast
== batch
.Batch
.OSD
.VolSpec('/dev/db',
298 def test_add_very_fast(self
):
299 osd
= batch
.Batch
.OSD('/dev/data', 1, '5G', 1, 1, None)
300 osd
.add_very_fast_device('/dev/wal', 1, '5G', 1)
301 assert osd
.very_fast
== batch
.Batch
.OSD
.VolSpec('/dev/wal',