]>
git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/tests/util/test_device.py
2 from copy
import deepcopy
3 from ceph_volume
.util
import device
4 from ceph_volume
.api
import lvm
as api
7 class TestDevice(object):
9 def test_sys_api(self
, monkeypatch
, device_info
):
10 volume
= api
.Volume(lv_name
='lv', lv_uuid
='y', vg_name
='vg',
11 lv_tags
={}, lv_path
='/dev/VolGroup/lv')
13 volumes
.append(volume
)
14 monkeypatch
.setattr(api
, 'get_lvs', lambda **kwargs
:
17 data
= {"/dev/sda": {"foo": "bar"}}
18 device_info(devices
=data
)
19 disk
= device
.Device("/dev/sda")
21 assert "foo" in disk
.sys_api
23 def test_lvm_size(self
, monkeypatch
, device_info
):
24 volume
= api
.Volume(lv_name
='lv', lv_uuid
='y', vg_name
='vg',
25 lv_tags
={}, lv_path
='/dev/VolGroup/lv')
27 volumes
.append(volume
)
28 monkeypatch
.setattr(api
, 'get_lvs', lambda **kwargs
:
32 data
= {"/dev/sda": {"size": "5368709120"}}
33 device_info(devices
=data
)
34 disk
= device
.Device("/dev/sda")
35 assert disk
.lvm_size
.gb
== 4
37 def test_lvm_size_rounds_down(self
, device_info
):
39 data
= {"/dev/sda": {"size": "5905580032"}}
40 device_info(devices
=data
)
41 disk
= device
.Device("/dev/sda")
42 assert disk
.lvm_size
.gb
== 4
44 def test_is_lv(self
, device_info
):
45 data
= {"lv_path": "vg/lv", "vg_name": "vg", "name": "lv"}
47 disk
= device
.Device("vg/lv")
50 def test_vgs_is_empty(self
, device_info
, monkeypatch
):
51 BarPVolume
= api
.PVolume(pv_name
='/dev/sda', pv_uuid
="0000",
54 pvolumes
.append(BarPVolume
)
55 lsblk
= {"TYPE": "disk"}
56 device_info(lsblk
=lsblk
)
57 monkeypatch
.setattr(api
, 'get_pvs', lambda **kwargs
: {})
59 disk
= device
.Device("/dev/nvme0n1")
62 def test_vgs_is_not_empty(self
, device_info
, monkeypatch
):
63 vg
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=6,
64 vg_extent_size
=1073741824)
65 monkeypatch
.setattr(api
, 'get_device_vgs', lambda x
: [vg
])
66 lsblk
= {"TYPE": "disk"}
67 device_info(lsblk
=lsblk
)
68 disk
= device
.Device("/dev/nvme0n1")
69 assert len(disk
.vgs
) == 1
71 def test_device_is_device(self
, device_info
):
72 data
= {"/dev/sda": {"foo": "bar"}}
73 lsblk
= {"TYPE": "device"}
74 device_info(devices
=data
, lsblk
=lsblk
)
75 disk
= device
.Device("/dev/sda")
76 assert disk
.is_device
is True
78 def test_device_is_rotational(self
, device_info
):
79 data
= {"/dev/sda": {"rotational": "1"}}
80 lsblk
= {"TYPE": "device"}
81 device_info(devices
=data
, lsblk
=lsblk
)
82 disk
= device
.Device("/dev/sda")
83 assert disk
.rotational
85 def test_device_is_not_rotational(self
, device_info
):
86 data
= {"/dev/sda": {"rotational": "0"}}
87 lsblk
= {"TYPE": "device"}
88 device_info(devices
=data
, lsblk
=lsblk
)
89 disk
= device
.Device("/dev/sda")
90 assert not disk
.rotational
92 def test_device_is_rotational_lsblk(self
, device_info
):
93 data
= {"/dev/sda": {"foo": "bar"}}
94 lsblk
= {"TYPE": "device", "ROTA": "1"}
95 device_info(devices
=data
, lsblk
=lsblk
)
96 disk
= device
.Device("/dev/sda")
97 assert disk
.rotational
99 def test_device_is_not_rotational_lsblk(self
, device_info
):
100 data
= {"/dev/sda": {"rotational": "0"}}
101 lsblk
= {"TYPE": "device", "ROTA": "0"}
102 device_info(devices
=data
, lsblk
=lsblk
)
103 disk
= device
.Device("/dev/sda")
104 assert not disk
.rotational
106 def test_device_is_rotational_defaults_true(self
, device_info
):
107 # rotational will default true if no info from sys_api or lsblk is found
108 data
= {"/dev/sda": {"foo": "bar"}}
109 lsblk
= {"TYPE": "device", "foo": "bar"}
110 device_info(devices
=data
, lsblk
=lsblk
)
111 disk
= device
.Device("/dev/sda")
112 assert disk
.rotational
114 def test_disk_is_device(self
, device_info
):
115 data
= {"/dev/sda": {"foo": "bar"}}
116 lsblk
= {"TYPE": "disk"}
117 device_info(devices
=data
, lsblk
=lsblk
)
118 disk
= device
.Device("/dev/sda")
119 assert disk
.is_device
is True
121 def test_is_partition(self
, device_info
):
122 data
= {"/dev/sda": {"foo": "bar"}}
123 lsblk
= {"TYPE": "part"}
124 device_info(devices
=data
, lsblk
=lsblk
)
125 disk
= device
.Device("/dev/sda")
126 assert disk
.is_partition
128 def test_is_not_acceptable_device(self
, device_info
):
129 data
= {"/dev/dm-0": {"foo": "bar"}}
130 lsblk
= {"TYPE": "mpath"}
131 device_info(devices
=data
, lsblk
=lsblk
)
132 disk
= device
.Device("/dev/dm-0")
133 assert not disk
.is_device
135 def test_is_not_lvm_memeber(self
, device_info
):
136 data
= {"/dev/sda": {"foo": "bar"}}
137 lsblk
= {"TYPE": "part"}
138 device_info(devices
=data
, lsblk
=lsblk
)
139 disk
= device
.Device("/dev/sda")
140 assert not disk
.is_lvm_member
142 def test_is_lvm_memeber(self
, device_info
):
143 data
= {"/dev/sda": {"foo": "bar"}}
144 lsblk
= {"TYPE": "part"}
145 device_info(devices
=data
, lsblk
=lsblk
)
146 disk
= device
.Device("/dev/sda")
147 assert not disk
.is_lvm_member
149 def test_is_mapper_device(self
, device_info
):
151 disk
= device
.Device("/dev/mapper/foo")
152 assert disk
.is_mapper
154 def test_dm_is_mapper_device(self
, device_info
):
156 disk
= device
.Device("/dev/dm-4")
157 assert disk
.is_mapper
159 def test_is_not_mapper_device(self
, device_info
):
161 disk
= device
.Device("/dev/sda")
162 assert not disk
.is_mapper
164 @pytest.mark
.usefixtures("lsblk_ceph_disk_member",
165 "disable_kernel_queries")
166 def test_is_ceph_disk_lsblk(self
, monkeypatch
, patch_bluestore_label
):
167 disk
= device
.Device("/dev/sda")
168 assert disk
.is_ceph_disk_member
170 @pytest.mark
.usefixtures("blkid_ceph_disk_member",
171 "disable_kernel_queries")
172 def test_is_ceph_disk_blkid(self
, monkeypatch
, patch_bluestore_label
):
173 monkeypatch
.setattr("ceph_volume.util.device.disk.lsblk",
174 lambda path
: {'PARTLABEL': ""})
175 disk
= device
.Device("/dev/sda")
176 assert disk
.is_ceph_disk_member
178 @pytest.mark
.usefixtures("lsblk_ceph_disk_member",
179 "disable_kernel_queries")
180 def test_is_ceph_disk_member_not_available_lsblk(self
, monkeypatch
, patch_bluestore_label
):
181 disk
= device
.Device("/dev/sda")
182 assert disk
.is_ceph_disk_member
183 assert not disk
.available
184 assert "Used by ceph-disk" in disk
.rejected_reasons
186 @pytest.mark
.usefixtures("blkid_ceph_disk_member",
187 "disable_kernel_queries")
188 def test_is_ceph_disk_member_not_available_blkid(self
, monkeypatch
, patch_bluestore_label
):
189 monkeypatch
.setattr("ceph_volume.util.device.disk.lsblk",
190 lambda path
: {'PARTLABEL': ""})
191 disk
= device
.Device("/dev/sda")
192 assert disk
.is_ceph_disk_member
193 assert not disk
.available
194 assert "Used by ceph-disk" in disk
.rejected_reasons
196 def test_reject_removable_device(self
, device_info
):
197 data
= {"/dev/sdb": {"removable": 1}}
198 device_info(devices
=data
)
199 disk
= device
.Device("/dev/sdb")
200 assert not disk
.available
202 def test_accept_non_removable_device(self
, device_info
):
203 data
= {"/dev/sdb": {"removable": 0, "size": 5368709120}}
204 device_info(devices
=data
)
205 disk
= device
.Device("/dev/sdb")
206 assert disk
.available
208 def test_reject_readonly_device(self
, device_info
):
209 data
= {"/dev/cdrom": {"ro": 1}}
210 device_info(devices
=data
)
211 disk
= device
.Device("/dev/cdrom")
212 assert not disk
.available
214 def test_reject_smaller_than_5gb(self
, device_info
):
215 data
= {"/dev/sda": {"size": 5368709119}}
216 device_info(devices
=data
)
217 disk
= device
.Device("/dev/sda")
218 assert not disk
.available
, 'too small device is available'
220 def test_accept_non_readonly_device(self
, device_info
):
221 data
= {"/dev/sda": {"ro": 0, "size": 5368709120}}
222 device_info(devices
=data
)
223 disk
= device
.Device("/dev/sda")
224 assert disk
.available
226 def test_reject_bluestore_device(self
, monkeypatch
, patch_bluestore_label
):
227 patch_bluestore_label
.return_value
= True
228 disk
= device
.Device("/dev/sda")
229 assert not disk
.available
230 assert "Has BlueStore device label" in disk
.rejected_reasons
232 @pytest.mark
.usefixtures("device_info_not_ceph_disk_member",
233 "disable_kernel_queries")
234 def test_is_not_ceph_disk_member_lsblk(self
, patch_bluestore_label
):
235 disk
= device
.Device("/dev/sda")
236 assert disk
.is_ceph_disk_member
is False
238 def test_existing_vg_available(self
, monkeypatch
, device_info
):
239 vg
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=6,
240 vg_extent_size
=1073741824)
241 monkeypatch
.setattr(api
, 'get_device_vgs', lambda x
: [vg
])
242 lsblk
= {"TYPE": "disk"}
243 data
= {"/dev/nvme0n1": {"size": "6442450944"}}
244 device_info(devices
=data
, lsblk
=lsblk
)
245 disk
= device
.Device("/dev/nvme0n1")
246 assert disk
.available_lvm
247 assert not disk
.available
248 assert not disk
.available_raw
250 def test_existing_vg_too_small(self
, monkeypatch
, device_info
):
251 vg
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=4,
252 vg_extent_size
=1073741824)
253 monkeypatch
.setattr(api
, 'get_device_vgs', lambda x
: [vg
])
254 lsblk
= {"TYPE": "disk"}
255 data
= {"/dev/nvme0n1": {"size": "6442450944"}}
256 device_info(devices
=data
, lsblk
=lsblk
)
257 disk
= device
.Device("/dev/nvme0n1")
258 assert not disk
.available_lvm
259 assert not disk
.available
260 assert not disk
.available_raw
262 def test_multiple_existing_vgs(self
, monkeypatch
, device_info
):
263 vg1
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=4,
264 vg_extent_size
=1073741824)
265 vg2
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=6,
266 vg_extent_size
=1073741824)
267 monkeypatch
.setattr(api
, 'get_device_vgs', lambda x
: [vg1
, vg2
])
268 lsblk
= {"TYPE": "disk"}
269 data
= {"/dev/nvme0n1": {"size": "6442450944"}}
270 device_info(devices
=data
, lsblk
=lsblk
)
271 disk
= device
.Device("/dev/nvme0n1")
272 assert disk
.available_lvm
273 assert not disk
.available
274 assert not disk
.available_raw
276 @pytest.mark
.parametrize("ceph_type", ["data", "block"])
277 def test_used_by_ceph(self
, device_info
,
278 monkeypatch
, ceph_type
):
279 data
= {"/dev/sda": {"foo": "bar"}}
280 lsblk
= {"TYPE": "part"}
281 FooPVolume
= api
.PVolume(pv_name
='/dev/sda', pv_uuid
="0000",
282 lv_uuid
="0000", pv_tags
={}, vg_name
="vg")
284 pvolumes
.append(FooPVolume
)
285 lv_data
= {"lv_name": "lv", "lv_path": "vg/lv", "vg_name": "vg",
286 "lv_uuid": "0000", "lv_tags":
287 "ceph.osd_id=0,ceph.type="+ceph_type
}
289 lv
= api
.Volume(**lv_data
)
291 monkeypatch
.setattr(api
, 'get_pvs', lambda **kwargs
: pvolumes
)
292 monkeypatch
.setattr(api
, 'get_lvs', lambda **kwargs
:
295 device_info(devices
=data
, lsblk
=lsblk
, lv
=lv_data
)
296 vg
= api
.VolumeGroup(vg_name
='foo/bar', vg_free_count
=6,
297 vg_extent_size
=1073741824)
298 monkeypatch
.setattr(api
, 'get_device_vgs', lambda x
: [vg
])
299 disk
= device
.Device("/dev/sda")
300 assert disk
.used_by_ceph
302 def test_not_used_by_ceph(self
, device_info
, monkeypatch
):
303 FooPVolume
= api
.PVolume(pv_name
='/dev/sda', pv_uuid
="0000", lv_uuid
="0000", pv_tags
={}, vg_name
="vg")
305 pvolumes
.append(FooPVolume
)
306 data
= {"/dev/sda": {"foo": "bar"}}
307 lsblk
= {"TYPE": "part"}
308 lv_data
= {"lv_path": "vg/lv", "vg_name": "vg", "lv_uuid": "0000", "tags": {"ceph.osd_id": 0, "ceph.type": "journal"}}
309 monkeypatch
.setattr(api
, 'get_pvs', lambda **kwargs
: pvolumes
)
311 device_info(devices
=data
, lsblk
=lsblk
, lv
=lv_data
)
312 disk
= device
.Device("/dev/sda")
313 assert not disk
.used_by_ceph
315 def test_get_device_id(self
, device_info
):
316 udev
= {k
:k
for k
in ['ID_VENDOR', 'ID_MODEL', 'ID_SCSI_SERIAL']}
317 device_info(udevadm
=udev
)
318 disk
= device
.Device("/dev/sda")
319 assert disk
._get
_device
_id
() == 'ID_VENDOR_ID_MODEL_ID_SCSI_SERIAL'
323 class TestDeviceEncryption(object):
325 def test_partition_is_not_encrypted_lsblk(self
, device_info
):
326 lsblk
= {'TYPE': 'part', 'FSTYPE': 'xfs'}
327 device_info(lsblk
=lsblk
)
328 disk
= device
.Device("/dev/sda")
329 assert disk
.is_encrypted
is False
331 def test_partition_is_encrypted_lsblk(self
, device_info
):
332 lsblk
= {'TYPE': 'part', 'FSTYPE': 'crypto_LUKS'}
333 device_info(lsblk
=lsblk
)
334 disk
= device
.Device("/dev/sda")
335 assert disk
.is_encrypted
is True
337 def test_partition_is_not_encrypted_blkid(self
, device_info
):
338 lsblk
= {'TYPE': 'part'}
339 blkid
= {'TYPE': 'ceph data'}
340 device_info(lsblk
=lsblk
, blkid
=blkid
)
341 disk
= device
.Device("/dev/sda")
342 assert disk
.is_encrypted
is False
344 def test_partition_is_encrypted_blkid(self
, device_info
):
345 lsblk
= {'TYPE': 'part'}
346 blkid
= {'TYPE': 'crypto_LUKS'}
347 device_info(lsblk
=lsblk
, blkid
=blkid
)
348 disk
= device
.Device("/dev/sda")
349 assert disk
.is_encrypted
is True
351 def test_mapper_is_encrypted_luks1(self
, device_info
, monkeypatch
):
352 status
= {'type': 'LUKS1'}
353 monkeypatch
.setattr(device
, 'encryption_status', lambda x
: status
)
354 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
355 blkid
= {'TYPE': 'mapper'}
356 device_info(lsblk
=lsblk
, blkid
=blkid
)
357 disk
= device
.Device("/dev/mapper/uuid")
358 assert disk
.is_encrypted
is True
360 def test_mapper_is_encrypted_luks2(self
, device_info
, monkeypatch
):
361 status
= {'type': 'LUKS2'}
362 monkeypatch
.setattr(device
, 'encryption_status', lambda x
: status
)
363 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
364 blkid
= {'TYPE': 'mapper'}
365 device_info(lsblk
=lsblk
, blkid
=blkid
)
366 disk
= device
.Device("/dev/mapper/uuid")
367 assert disk
.is_encrypted
is True
369 def test_mapper_is_encrypted_plain(self
, device_info
, monkeypatch
):
370 status
= {'type': 'PLAIN'}
371 monkeypatch
.setattr(device
, 'encryption_status', lambda x
: status
)
372 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
373 blkid
= {'TYPE': 'mapper'}
374 device_info(lsblk
=lsblk
, blkid
=blkid
)
375 disk
= device
.Device("/dev/mapper/uuid")
376 assert disk
.is_encrypted
is True
378 def test_mapper_is_not_encrypted_plain(self
, device_info
, monkeypatch
):
379 monkeypatch
.setattr(device
, 'encryption_status', lambda x
: {})
380 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
381 blkid
= {'TYPE': 'mapper'}
382 device_info(lsblk
=lsblk
, blkid
=blkid
)
383 disk
= device
.Device("/dev/mapper/uuid")
384 assert disk
.is_encrypted
is False
386 def test_lv_is_encrypted_blkid(self
, device_info
):
387 lsblk
= {'TYPE': 'lvm'}
388 blkid
= {'TYPE': 'crypto_LUKS'}
389 device_info(lsblk
=lsblk
, blkid
=blkid
)
390 disk
= device
.Device("/dev/sda")
392 assert disk
.is_encrypted
is True
394 def test_lv_is_not_encrypted_blkid(self
, factory
, device_info
):
395 lsblk
= {'TYPE': 'lvm'}
396 blkid
= {'TYPE': 'xfs'}
397 device_info(lsblk
=lsblk
, blkid
=blkid
)
398 disk
= device
.Device("/dev/sda")
399 disk
.lv_api
= factory(encrypted
=None)
400 assert disk
.is_encrypted
is False
402 def test_lv_is_encrypted_lsblk(self
, device_info
):
403 lsblk
= {'FSTYPE': 'crypto_LUKS', 'TYPE': 'lvm'}
404 blkid
= {'TYPE': 'mapper'}
405 device_info(lsblk
=lsblk
, blkid
=blkid
)
406 disk
= device
.Device("/dev/sda")
408 assert disk
.is_encrypted
is True
410 def test_lv_is_not_encrypted_lsblk(self
, factory
, device_info
):
411 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
412 blkid
= {'TYPE': 'mapper'}
413 device_info(lsblk
=lsblk
, blkid
=blkid
)
414 disk
= device
.Device("/dev/sda")
415 disk
.lv_api
= factory(encrypted
=None)
416 assert disk
.is_encrypted
is False
418 def test_lv_is_encrypted_lvm_api(self
, factory
, device_info
):
419 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
420 blkid
= {'TYPE': 'mapper'}
421 device_info(lsblk
=lsblk
, blkid
=blkid
)
422 disk
= device
.Device("/dev/sda")
423 disk
.lv_api
= factory(encrypted
=True)
424 assert disk
.is_encrypted
is True
426 def test_lv_is_not_encrypted_lvm_api(self
, factory
, device_info
):
427 lsblk
= {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
428 blkid
= {'TYPE': 'mapper'}
429 device_info(lsblk
=lsblk
, blkid
=blkid
)
430 disk
= device
.Device("/dev/sda")
431 disk
.lv_api
= factory(encrypted
=False)
432 assert disk
.is_encrypted
is False
435 class TestDeviceOrdering(object):
439 "/dev/sda": {"removable": 0},
440 "/dev/sdb": {"removable": 1}, # invalid
441 "/dev/sdc": {"removable": 0},
442 "/dev/sdd": {"removable": 1}, # invalid
445 def test_valid_before_invalid(self
, device_info
):
446 device_info(devices
=self
.data
)
447 sda
= device
.Device("/dev/sda")
448 sdb
= device
.Device("/dev/sdb")
453 def test_valid_alphabetical_ordering(self
, device_info
):
454 device_info(devices
=self
.data
)
455 sda
= device
.Device("/dev/sda")
456 sdc
= device
.Device("/dev/sdc")
461 def test_invalid_alphabetical_ordering(self
, device_info
):
462 device_info(devices
=self
.data
)
463 sdb
= device
.Device("/dev/sdb")
464 sdd
= device
.Device("/dev/sdd")
470 class TestCephDiskDevice(object):
472 def test_partlabel_lsblk(self
, device_info
):
473 lsblk
= {"PARTLABEL": ""}
474 device_info(lsblk
=lsblk
)
475 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
477 assert disk
.partlabel
== ''
479 def test_partlabel_blkid(self
, device_info
):
480 lsblk
= {"PARTLABEL": ""}
481 blkid
= {"PARTLABEL": "ceph data"}
482 device_info(lsblk
=lsblk
, blkid
=blkid
)
483 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
485 assert disk
.partlabel
== 'ceph data'
487 @pytest.mark
.usefixtures("blkid_ceph_disk_member",
488 "disable_kernel_queries")
489 def test_is_member_blkid(self
, monkeypatch
, patch_bluestore_label
):
490 monkeypatch
.setattr("ceph_volume.util.device.disk.lsblk",
491 lambda path
: {'PARTLABEL': ""})
492 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
494 assert disk
.is_member
is True
496 @pytest.mark
.usefixtures("lsblk_ceph_disk_member",
497 "disable_kernel_queries")
498 def test_is_member_lsblk(self
, patch_bluestore_label
):
499 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
501 assert disk
.is_member
is True
503 def test_unknown_type(self
, device_info
):
504 lsblk
= {"PARTLABEL": "gluster"}
505 device_info(lsblk
=lsblk
)
506 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
508 assert disk
.type == 'unknown'
510 ceph_types
= ['data', 'wal', 'db', 'lockbox', 'journal', 'block']
512 @pytest.mark
.usefixtures("blkid_ceph_disk_member",
513 "disable_kernel_queries")
514 def test_type_blkid(self
, monkeypatch
, device_info
, ceph_partlabel
):
515 monkeypatch
.setattr("ceph_volume.util.device.disk.lsblk",
516 lambda path
: {'PARTLABEL': ''})
517 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
519 assert disk
.type in self
.ceph_types
521 @pytest.mark
.usefixtures("blkid_ceph_disk_member",
522 "lsblk_ceph_disk_member",
523 "disable_kernel_queries")
524 def test_type_lsblk(self
, device_info
, ceph_partlabel
):
525 disk
= device
.CephDiskDevice(device
.Device("/dev/sda"))
527 assert disk
.type in self
.ceph_types