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(
35 has_gpt_headers
=False,
37 with pytest
.raises(ArgumentError
):
38 arg_validators
.ValidBatchDevice()('foo')
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,
58 plan
= b
.get_plan(args
)
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')
67 args
= factory(data_slots
=1,
80 plan
= b
.get_plan(args
)
82 report
= b
._create
_report
(plan
)
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,
105 plan
= b
.get_plan(args
)
107 report
= b
._create
_report
(plan
)
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,
125 db_devices
=fast_devs
,
126 wal_devices
=very_fast_devs
,
132 plan
= b
.get_plan(args
)
134 report
= b
._create
_report
(plan
)
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,
149 b
._sort
_rotational
_disks
()
150 assert len(b
.args
.devices
) == 3
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,
160 filestore
=False if objectstore
== 'bluestore' else True,
164 b
._sort
_rotational
_disks
()
165 assert len(b
.args
.devices
) == 2
166 if objectstore
== 'bluestore':
167 assert len(b
.args
.db_devices
) == 1
169 assert len(b
.args
.journal_devices
) == 1
171 def test_get_physical_osds_return_len(self
, factory
,
172 mock_devices_available
,
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
181 def test_get_physical_osds_rel_size(self
, factory
,
182 mock_devices_available
,
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
)
189 assert osd
.data
[1] == 1.0 / osds_per_device
191 def test_get_physical_osds_abs_size(self
, factory
,
192 mock_devices_available
,
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
)
202 def test_get_physical_osds_osd_ids(self
, factory
,
203 mock_devices_available
,
207 def test_get_physical_fast_allocs_length(self
, factory
,
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
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')
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
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
,
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
)]
239 while already_assigned
< occupied_prior
:
240 dev_i
= random
.randint(0, num_devs
- 1)
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
,
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
256 def test_get_lvm_osds_return_len(self
, factory
,
257 mock_lv_device_generator
,
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
268 class TestBatchOsd(object):
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',
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',
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',