]>
git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/tests/util/test_disk.py
5d1bd82b60217b30a4d04e4c7c1cc2344d97d977
3 from ceph_volume
.util
import disk
6 class TestLsblkParser(object):
8 def test_parses_whitespace_values(self
):
9 output
= 'NAME="sdaa5" PARTLABEL="ceph data" RM="0" SIZE="10M" RO="0" TYPE="part"'
10 result
= disk
._lsblk
_parser
(output
)
11 assert result
['PARTLABEL'] == 'ceph data'
13 def test_ignores_bogus_pairs(self
):
14 output
= 'NAME="sdaa5" PARTLABEL RM="0" SIZE="10M" RO="0" TYPE="part" MOUNTPOINT=""'
15 result
= disk
._lsblk
_parser
(output
)
16 assert result
['SIZE'] == '10M'
19 class TestBlkidParser(object):
21 def test_parses_whitespace_values(self
):
22 output
= '''/dev/sdb1: UUID="62416664-cbaf-40bd-9689-10bd337379c3" TYPE="xfs" PART_ENTRY_SCHEME="gpt" PART_ENTRY_NAME="ceph data" PART_ENTRY_UUID="b89c03bc-bf58-4338-a8f8-a2f484852b4f"''' # noqa
23 result
= disk
._blkid
_parser
(output
)
24 assert result
['PARTLABEL'] == 'ceph data'
26 def test_ignores_unmapped(self
):
27 output
= '''/dev/sdb1: UUID="62416664-cbaf-40bd-9689-10bd337379c3" TYPE="xfs" PART_ENTRY_SCHEME="gpt" PART_ENTRY_NAME="ceph data" PART_ENTRY_UUID="b89c03bc-bf58-4338-a8f8-a2f484852b4f"''' # noqa
28 result
= disk
._blkid
_parser
(output
)
29 assert len(result
.keys()) == 4
31 def test_translates_to_partuuid(self
):
32 output
= '''/dev/sdb1: UUID="62416664-cbaf-40bd-9689-10bd337379c3" TYPE="xfs" PART_ENTRY_SCHEME="gpt" PART_ENTRY_NAME="ceph data" PART_ENTRY_UUID="b89c03bc-bf58-4338-a8f8-a2f484852b4f"''' # noqa
33 result
= disk
._blkid
_parser
(output
)
34 assert result
['PARTUUID'] == 'b89c03bc-bf58-4338-a8f8-a2f484852b4f'
37 class TestBlkid(object):
39 def test_parses_translated(self
, stub_call
):
40 output
= '''/dev/sdb1: UUID="62416664-cbaf-40bd-9689-10bd337379c3" TYPE="xfs" PART_ENTRY_SCHEME="gpt" PART_ENTRY_NAME="ceph data" PART_ENTRY_UUID="b89c03bc-bf58-4338-a8f8-a2f484852b4f"''' # noqa
41 stub_call((output
.split(), [], 0))
42 result
= disk
.blkid('/dev/sdb1')
43 assert result
['PARTUUID'] == 'b89c03bc-bf58-4338-a8f8-a2f484852b4f'
44 assert result
['PARTLABEL'] == 'ceph data'
45 assert result
['UUID'] == '62416664-cbaf-40bd-9689-10bd337379c3'
46 assert result
['TYPE'] == 'xfs'
49 class TestDeviceFamily(object):
51 def test_groups_multiple_devices(self
, stub_call
):
53 'NAME="sdaa5" PARLABEL="ceph lockbox"',
55 'NAME="sdaa1" PARLABEL="ceph data"',
56 'NAME="sdaa2" PARLABEL="ceph journal"',
58 stub_call((out
, '', 0))
59 result
= disk
.device_family('sdaa5')
60 assert len(result
) == 4
62 def test_parses_output_correctly(self
, stub_call
):
63 names
= ['sdaa', 'sdaa5', 'sdaa1', 'sdaa2']
65 'NAME="sdaa5" PARLABEL="ceph lockbox"',
67 'NAME="sdaa1" PARLABEL="ceph data"',
68 'NAME="sdaa2" PARLABEL="ceph journal"',
70 stub_call((out
, '', 0))
71 result
= disk
.device_family('sdaa5')
73 assert parsed
['NAME'] in names
76 class TestMapDevPaths(object):
78 def test_errors_return_empty_mapping(self
, tmpdir
):
79 bad_dir
= os
.path
.join(str(tmpdir
), 'nonexisting')
80 assert disk
._map
_dev
_paths
(bad_dir
) == {}
82 def test_base_name_and_abspath(self
, tmpfile
):
83 sda_path
= tmpfile(name
='sda', contents
='')
84 directory
= os
.path
.dirname(sda_path
)
85 result
= disk
._map
_dev
_paths
(directory
)
86 assert len(result
.keys()) == 1
87 assert result
['sda'] == sda_path
89 def test_abspath_included(self
, tmpfile
):
90 sda_path
= tmpfile(name
='sda', contents
='')
91 directory
= os
.path
.dirname(sda_path
)
92 result
= disk
._map
_dev
_paths
(directory
, include_abspath
=True)
93 assert sorted(result
.keys()) == sorted(['sda', sda_path
])
94 assert result
['sda'] == sda_path
95 assert result
[sda_path
] == 'sda'
97 def test_realpath_included(self
, tmpfile
):
98 sda_path
= tmpfile(name
='sda', contents
='')
99 directory
= os
.path
.dirname(sda_path
)
100 dm_path
= os
.path
.join(directory
, 'dm-0')
101 os
.symlink(sda_path
, os
.path
.join(directory
, 'dm-0'))
102 result
= disk
._map
_dev
_paths
(directory
, include_realpath
=True)
103 assert sorted(result
.keys()) == sorted(['sda', 'dm-0'])
104 assert result
['sda'] == dm_path
105 assert result
['dm-0'] == dm_path
107 def test_absolute_and_realpath_included(self
, tmpfile
):
108 dm_path
= tmpfile(name
='dm-0', contents
='')
109 directory
= os
.path
.dirname(dm_path
)
110 sda_path
= os
.path
.join(directory
, 'sda')
111 os
.symlink(sda_path
, os
.path
.join(directory
, 'sda'))
112 result
= disk
._map
_dev
_paths
(directory
, include_realpath
=True, include_abspath
=True)
113 assert sorted(result
.keys()) == sorted([dm_path
, sda_path
, 'sda', 'dm-0'])
114 assert result
['sda'] == sda_path
115 assert result
['dm-0'] == dm_path
116 assert result
[sda_path
] == sda_path
117 assert result
[dm_path
] == 'dm-0'
120 class TestGetBlockDevs(object):
122 def test_loop_devices_are_missing(self
, tmpfile
):
123 path
= os
.path
.dirname(tmpfile(name
='loop0', contents
=''))
124 result
= disk
.get_block_devs(sys_block_path
=path
)
127 def test_loop_devices_are_included(self
, tmpfile
):
128 path
= os
.path
.dirname(tmpfile(name
='loop0', contents
=''))
129 result
= disk
.get_block_devs(sys_block_path
=path
, skip_loop
=False)
130 assert len(result
) == 1
131 assert result
== ['loop0']
134 class TestGetDevDevs(object):
136 def test_abspaths_are_included(self
, tmpfile
):
137 sda_path
= tmpfile(name
='sda', contents
='')
138 directory
= os
.path
.dirname(sda_path
)
139 result
= disk
.get_dev_devs(directory
)
140 assert sorted(result
.keys()) == sorted(['sda', sda_path
])
141 assert result
['sda'] == sda_path
142 assert result
[sda_path
] == 'sda'
145 class TestGetMapperDevs(object):
147 def test_abspaths_and_realpaths_are_included(self
, tmpfile
):
148 dm_path
= tmpfile(name
='dm-0', contents
='')
149 directory
= os
.path
.dirname(dm_path
)
150 sda_path
= os
.path
.join(directory
, 'sda')
151 os
.symlink(sda_path
, os
.path
.join(directory
, 'sda'))
152 result
= disk
.get_mapper_devs(directory
)
153 assert sorted(result
.keys()) == sorted([dm_path
, sda_path
, 'sda', 'dm-0'])
154 assert result
['sda'] == sda_path
155 assert result
['dm-0'] == dm_path
156 assert result
[sda_path
] == sda_path
157 assert result
[dm_path
] == 'dm-0'
160 class TestHumanReadableSize(object):
162 def test_bytes(self
):
163 result
= disk
.human_readable_size(800)
164 assert result
== '800.00 B'
166 def test_kilobytes(self
):
167 result
= disk
.human_readable_size(800*1024)
168 assert result
== '800.00 KB'
170 def test_megabytes(self
):
171 result
= disk
.human_readable_size(800*1024*1024)
172 assert result
== '800.00 MB'
174 def test_gigabytes(self
):
175 result
= disk
.human_readable_size(8.19*1024*1024*1024)
176 assert result
== '8.19 GB'
178 def test_terabytes(self
):
179 result
= disk
.human_readable_size(81.2*1024*1024*1024*1024)
180 assert result
== '81.20 TB'
183 class TestGetDevices(object):
185 def setup_paths(self
, tmpdir
):
187 for directory
in ['block', 'dev', 'mapper']:
188 path
= os
.path
.join(str(tmpdir
), directory
)
193 def test_no_devices_are_found(self
, tmpdir
):
194 result
= disk
.get_devices(
195 _sys_block_path
=str(tmpdir
),
196 _dev_path
=str(tmpdir
),
197 _mapper_path
=str(tmpdir
))
200 def test_no_devices_are_found_errors(self
, tmpdir
):
201 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
202 os
.makedirs(os
.path
.join(block_path
, 'sda'))
203 result
= disk
.get_devices(
204 _sys_block_path
=block_path
, # has 1 device
205 _dev_path
=str(tmpdir
), # exists but no devices
206 _mapper_path
='/does/not/exist/path') # does not exist
209 def test_sda_block_is_found(self
, tmpfile
, tmpdir
):
210 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
211 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
212 os
.makedirs(os
.path
.join(block_path
, 'sda'))
213 os
.makedirs(dev_sda_path
)
214 result
= disk
.get_devices(
215 _sys_block_path
=block_path
,
217 _mapper_path
=mapper_path
)
218 assert len(result
.keys()) == 1
219 assert result
[dev_sda_path
]['human_readable_size'] == '0.00 B'
220 assert result
[dev_sda_path
]['model'] == ''
221 assert result
[dev_sda_path
]['partitions'] == {}
224 def test_dm_device_is_not_used(self
, monkeypatch
, tmpdir
):
225 # the link to the mapper is used instead
226 monkeypatch
.setattr(disk
.lvm
, 'is_lv', lambda: True)
227 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
228 dev_dm_path
= os
.path
.join(dev_path
, 'dm-0')
229 ceph_data_path
= os
.path
.join(mapper_path
, 'ceph-data')
230 os
.symlink(dev_dm_path
, ceph_data_path
)
231 block_dm_path
= os
.path
.join(block_path
, 'dm-0')
232 os
.makedirs(block_dm_path
)
234 result
= disk
.get_devices(
235 _sys_block_path
=block_path
,
237 _mapper_path
=mapper_path
)
238 result
= list(result
.keys())
239 assert len(result
) == 1
240 assert result
== [ceph_data_path
]
242 def test_sda_size(self
, tmpfile
, tmpdir
):
243 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
244 block_sda_path
= os
.path
.join(block_path
, 'sda')
245 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
246 os
.makedirs(block_sda_path
)
247 os
.makedirs(dev_sda_path
)
248 tmpfile('size', '1024', directory
=block_sda_path
)
249 result
= disk
.get_devices(
250 _sys_block_path
=block_path
,
252 _mapper_path
=mapper_path
)
253 assert list(result
.keys()) == [dev_sda_path
]
254 assert result
[dev_sda_path
]['human_readable_size'] == '512.00 KB'
256 def test_sda_sectorsize_fallsback(self
, tmpfile
, tmpdir
):
257 # if no sectorsize, it will use queue/hw_sector_size
258 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
259 block_sda_path
= os
.path
.join(block_path
, 'sda')
260 sda_queue_path
= os
.path
.join(block_sda_path
, 'queue')
261 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
262 os
.makedirs(block_sda_path
)
263 os
.makedirs(sda_queue_path
)
264 os
.makedirs(dev_sda_path
)
265 tmpfile('hw_sector_size', contents
='1024', directory
=sda_queue_path
)
266 result
= disk
.get_devices(
267 _sys_block_path
=block_path
,
269 _mapper_path
=mapper_path
)
270 assert list(result
.keys()) == [dev_sda_path
]
271 assert result
[dev_sda_path
]['sectorsize'] == '1024'
273 def test_sda_sectorsize_from_logical_block(self
, tmpfile
, tmpdir
):
274 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
275 block_sda_path
= os
.path
.join(block_path
, 'sda')
276 sda_queue_path
= os
.path
.join(block_sda_path
, 'queue')
277 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
278 os
.makedirs(block_sda_path
)
279 os
.makedirs(sda_queue_path
)
280 os
.makedirs(dev_sda_path
)
281 tmpfile('logical_block_size', contents
='99', directory
=sda_queue_path
)
282 result
= disk
.get_devices(
283 _sys_block_path
=block_path
,
285 _mapper_path
=mapper_path
)
286 assert result
[dev_sda_path
]['sectorsize'] == '99'
288 def test_sda_sectorsize_does_not_fallback(self
, tmpfile
, tmpdir
):
289 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
290 block_sda_path
= os
.path
.join(block_path
, 'sda')
291 sda_queue_path
= os
.path
.join(block_sda_path
, 'queue')
292 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
293 os
.makedirs(block_sda_path
)
294 os
.makedirs(sda_queue_path
)
295 os
.makedirs(dev_sda_path
)
296 tmpfile('logical_block_size', contents
='99', directory
=sda_queue_path
)
297 tmpfile('hw_sector_size', contents
='1024', directory
=sda_queue_path
)
298 result
= disk
.get_devices(
299 _sys_block_path
=block_path
,
301 _mapper_path
=mapper_path
)
302 assert result
[dev_sda_path
]['sectorsize'] == '99'
304 def test_is_rotational(self
, tmpfile
, tmpdir
):
305 block_path
, dev_path
, mapper_path
= self
.setup_paths(tmpdir
)
306 block_sda_path
= os
.path
.join(block_path
, 'sda')
307 sda_queue_path
= os
.path
.join(block_sda_path
, 'queue')
308 dev_sda_path
= os
.path
.join(dev_path
, 'sda')
309 os
.makedirs(block_sda_path
)
310 os
.makedirs(sda_queue_path
)
311 os
.makedirs(dev_sda_path
)
312 tmpfile('rotational', contents
='1', directory
=sda_queue_path
)
313 result
= disk
.get_devices(
314 _sys_block_path
=block_path
,
316 _mapper_path
=mapper_path
)
317 assert result
[dev_sda_path
]['rotational'] == '1'
320 class TestSizeCalculations(object):
322 @pytest.mark
.parametrize('aliases', [
329 def test_aliases(self
, aliases
):
330 short_alias
, long_alias
= aliases
332 short_alias
= getattr(s
, short_alias
)
333 long_alias
= getattr(s
, long_alias
)
334 assert short_alias
== long_alias
336 @pytest.mark
.parametrize('values', [
337 ('b', 857619069665.28),
338 ('kb', 837518622.72),
343 def test_terabytes(self
, values
):
344 # regardless of the input value, all the other values correlate to each
345 # other the same, every time
347 s
= disk
.Size(**{unit
: value
})
348 assert s
.b
== 857619069665.28
349 assert s
.kb
== 837518622.72
350 assert s
.mb
== 817889.28
351 assert s
.gb
== 798.72
355 class TestSizeOperators(object):
357 @pytest.mark
.parametrize('larger', [1025, 1024.1, 1024.001])
358 def test_gigabytes_is_smaller(self
, larger
):
359 assert disk
.Size(gb
=1) < disk
.Size(mb
=larger
)
361 @pytest.mark
.parametrize('smaller', [1023, 1023.9, 1023.001])
362 def test_gigabytes_is_larger(self
, smaller
):
363 assert disk
.Size(gb
=1) > disk
.Size(mb
=smaller
)
365 @pytest.mark
.parametrize('larger', [1025, 1024.1, 1024.001, 1024])
366 def test_gigabytes_is_smaller_or_equal(self
, larger
):
367 assert disk
.Size(gb
=1) <= disk
.Size(mb
=larger
)
369 @pytest.mark
.parametrize('smaller', [1023, 1023.9, 1023.001, 1024])
370 def test_gigabytes_is_larger_or_equal(self
, smaller
):
371 assert disk
.Size(gb
=1) >= disk
.Size(mb
=smaller
)
373 @pytest.mark
.parametrize('values', [
374 ('b', 857619069665.28),
375 ('kb', 837518622.72),
380 def test_equality(self
, values
):
382 s
= disk
.Size(**{unit
: value
})
383 # both tb and b, since b is always calculated regardless, and is useful
385 assert disk
.Size(tb
=0.78) == s
386 assert disk
.Size(b
=857619069665.28) == s
388 @pytest.mark
.parametrize('values', [
389 ('b', 857619069665.28),
390 ('kb', 837518622.72),
395 def test_inequality(self
, values
):
397 s
= disk
.Size(**{unit
: value
})
398 # both tb and b, since b is always calculated regardless, and is useful
400 assert disk
.Size(tb
=1) != s
401 assert disk
.Size(b
=100) != s
404 class TestSizeOperations(object):
406 def test_assignment_addition_with_size_objects(self
):
407 result
= disk
.Size(mb
=256) + disk
.Size(gb
=1)
408 assert result
.gb
== 1.25
409 assert result
.gb
.as_int() == 1
410 assert result
.gb
.as_float() == 1.25
412 def test_self_addition_with_size_objects(self
):
413 base
= disk
.Size(mb
=256)
414 base
+= disk
.Size(gb
=1)
415 assert base
.gb
== 1.25
417 def test_self_addition_does_not_alter_state(self
):
418 base
= disk
.Size(mb
=256)
419 base
+ disk
.Size(gb
=1)
420 assert base
.mb
== 256
422 def test_addition_with_non_size_objects(self
):
423 with pytest
.raises(TypeError):
424 disk
.Size(mb
=100) + 4
426 def test_assignment_subtraction_with_size_objects(self
):
427 base
= disk
.Size(gb
=1)
428 base
-= disk
.Size(mb
=256)
429 assert base
.mb
== 768
431 def test_self_subtraction_does_not_alter_state(self
):
432 base
= disk
.Size(gb
=1)
433 base
- disk
.Size(mb
=256)
436 def test_subtraction_with_size_objects(self
):
437 result
= disk
.Size(gb
=1) - disk
.Size(mb
=256)
438 assert result
.mb
== 768
440 def test_subtraction_with_non_size_objects(self
):
441 with pytest
.raises(TypeError):
442 disk
.Size(mb
=100) - 4
444 def test_multiplication_with_size_objects(self
):
445 with pytest
.raises(TypeError):
446 disk
.Size(mb
=100) * disk
.Size(mb
=1)
448 def test_multiplication_with_non_size_objects(self
):
449 base
= disk
.Size(gb
=1)
451 assert result
.gb
== 2
452 assert result
.gb
.as_int() == 2
454 def test_division_with_size_objects(self
):
455 result
= disk
.Size(gb
=1) / disk
.Size(mb
=1)
456 assert int(result
) == 1024
458 def test_division_with_non_size_objects(self
):
459 base
= disk
.Size(gb
=1)
461 assert result
.mb
== 512
462 assert result
.mb
.as_int() == 512
464 def test_division_with_non_size_objects_without_state(self
):
465 base
= disk
.Size(gb
=1)
468 assert base
.gb
.as_int() == 1
471 class TestSizeAttributes(object):
473 def test_attribute_does_not_exist(self
):
474 with pytest
.raises(AttributeError):
475 disk
.Size(mb
=1).exabytes
478 class TestSizeFormatting(object):
480 def test_default_formatting_tb_to_b(self
):
481 size
= disk
.Size(tb
=0.0000000001)
483 assert result
== "109.95 B"
485 def test_default_formatting_tb_to_kb(self
):
486 size
= disk
.Size(tb
=0.00000001)
488 assert result
== "10.74 KB"
490 def test_default_formatting_tb_to_mb(self
):
491 size
= disk
.Size(tb
=0.000001)
493 assert result
== "1.05 MB"
495 def test_default_formatting_tb_to_gb(self
):
496 size
= disk
.Size(tb
=0.001)
498 assert result
== "1.02 GB"
500 def test_default_formatting_tb_to_tb(self
):
501 size
= disk
.Size(tb
=10)
503 assert result
== "10.00 TB"
506 class TestSizeSpecificFormatting(object):
508 def test_formatting_b(self
):
509 size
= disk
.Size(b
=2048)
510 result
= "%s" % size
.b
511 assert "%s" % size
.b
== "%s" % size
.bytes
512 assert result
== "2048.00 B"
514 def test_formatting_kb(self
):
515 size
= disk
.Size(kb
=5700)
516 result
= "%s" % size
.kb
517 assert "%s" % size
.kb
== "%s" % size
.kilobytes
518 assert result
== "5700.00 KB"
520 def test_formatting_mb(self
):
521 size
= disk
.Size(mb
=4000)
522 result
= "%s" % size
.mb
523 assert "%s" % size
.mb
== "%s" % size
.megabytes
524 assert result
== "4000.00 MB"
526 def test_formatting_gb(self
):
527 size
= disk
.Size(gb
=77777)
528 result
= "%s" % size
.gb
529 assert "%s" % size
.gb
== "%s" % size
.gigabytes
530 assert result
== "77777.00 GB"
532 def test_formatting_tb(self
):
533 size
= disk
.Size(tb
=1027)
534 result
= "%s" % size
.tb
535 assert "%s" % size
.tb
== "%s" % size
.terabytes
536 assert result
== "1027.00 TB"