1
0
mirror of https://gerrit.ovirt.org/vdsm synced 2026-02-05 12:46:23 +01:00
Files
vdsm/tests/hostdev_test.py
Tomasz Baranski 9e1ea54bea virt: Engine needs host device block path
In order to correctly build libvirt XML when a host device is used as a
disk using a block driver, the engine needs to know the disk's block
path used by host OS.

This patch maps the generic path to the block path and includes it in
the response to hostdevListByCaps.

Change-Id: Ia68e9f8406926080effa60003e57c2f51f580f10
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1793550
Signed-off-by: Tomasz Baranski <tbaransk@redhat.com>
2020-02-10 17:01:37 +00:00

275 lines
10 KiB
Python

#
# Copyright 2014-2020 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Refer to the README and COPYING files for full details of the license
#
from __future__ import absolute_import
from __future__ import division
import six
from vdsm.common import exception
from vdsm.common import xmlutils
from vdsm.virt.vmdevices import network, hwclass
from testlib import VdsmTestCase as TestCaseBase, XMLTestCase
from testlib import permutations, expandPermutations
from monkeypatch import MonkeyClass, MonkeyPatchScope
from testValidation import skipif
from vdsm.common import hooks
from vdsm.common import hostdev
from vdsm.common import libvirtconnection
import hostdevlib
@expandPermutations
@MonkeyClass(libvirtconnection, 'get', hostdevlib.Connection)
@MonkeyClass(hostdev, '_sriov_totalvfs', hostdevlib.fake_totalvfs)
@MonkeyClass(hostdev, '_pci_header_type', lambda _: 0)
@MonkeyClass(hooks, 'after_hostdev_list_by_caps', lambda json: json)
@MonkeyClass(hostdev, '_get_udev_block_mapping',
lambda: hostdevlib.UDEV_BLOCK_MAP)
class HostdevTests(TestCaseBase):
def testProcessDeviceParams(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.ADDITIONAL_DEVICE).XMLDesc()
)
self.assertEqual(
hostdevlib.ADDITIONAL_DEVICE_PROCESSED,
deviceXML
)
@skipif(six.PY3, "Not relevant in Python 3 libvirt")
# libvirt in Python 3 returns strings, so we don't deal with
# invalid coding anymore.
def testProcessDeviceParamsInvalidEncoding(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.COMPUTER_DEVICE).XMLDesc()
)
self.assertEqual(
hostdevlib.COMPUTER_DEVICE_PROCESSED,
deviceXML
)
def testProcessSRIOV_PFDeviceParams(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.SRIOV_PF).XMLDesc()
)
self.assertEqual(
hostdevlib.SRIOV_PF_PROCESSED,
deviceXML
)
def testProcessSRIOV_VFDeviceParams(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.SRIOV_VF).XMLDesc()
)
self.assertEqual(hostdevlib.SRIOV_VF_PROCESSED, deviceXML)
def testProcessNetDeviceParams(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.NET_DEVICE).XMLDesc()
)
self.assertEqual(hostdevlib.NET_DEVICE_PROCESSED, deviceXML)
def testProcessMdevDeviceParams(self):
deviceXML = hostdev._process_device_params(
libvirtconnection.get().nodeDeviceLookupByName(
hostdevlib.MDEV_DEVICE).XMLDesc()
)
self.assertEqual(hostdevlib.MDEV_DEVICE_PROCESSED, deviceXML)
def testGetDevicesFromLibvirt(self):
libvirt_devices, _ = hostdev._get_devices_from_libvirt()
self.assertEqual(hostdevlib.DEVICES_PROCESSED, libvirt_devices)
self.assertEqual(len(libvirt_devices),
len(hostdevlib.PCI_DEVICES) +
len(hostdevlib.USB_DEVICES) +
len(hostdevlib.SCSI_DEVICES))
@permutations([[''], [('pci',)], [('usb_device',)],
[('pci', 'usb_device')]])
def testListByCaps(self, caps):
devices = hostdev.list_by_caps(caps)
for cap in caps:
self.assertTrue(set(hostdevlib.DEVICES_BY_CAPS[cap].keys()).
issubset(set(devices.keys())))
@permutations([
# addr_type, addr, name
('usb', {'bus': '1', 'device': '2'}, 'usb_1_1'),
('usb', {'bus': '1', 'device': '10'}, 'usb_1_1_4'),
('pci', {'slot': '26', 'bus': '0', 'domain': '0', 'function': '0'},
'pci_0000_00_1a_0'),
('scsi', {'bus': '0', 'host': '1', 'lun': '0', 'target': '0'},
'scsi_1_0_0_0'),
])
def test_device_name_from_address(self, addr_type, addr, name):
# we need to make sure we scan all the devices (hence caps=None)
hostdev.list_by_caps()
self.assertEqual(
hostdev.device_name_from_address(addr_type, addr),
name
)
@MonkeyClass(libvirtconnection, 'get', hostdevlib.Connection.get)
@MonkeyClass(hostdev, '_sriov_totalvfs', hostdevlib.fake_totalvfs)
@MonkeyClass(hostdev, '_pci_header_type', lambda _: 0)
@MonkeyClass(hooks, 'after_hostdev_list_by_caps', lambda json: json)
class HostdevPerformanceTests(TestCaseBase):
def test_3k_storage_devices(self):
with hostdevlib.Connection.use_hostdev_tree():
self.assertEqual(
len(hostdev.list_by_caps()),
len(libvirtconnection.get().listAllDevices())
)
@expandPermutations
@MonkeyClass(libvirtconnection, 'get', hostdevlib.Connection)
@MonkeyClass(hostdev, '_sriov_totalvfs', hostdevlib.fake_totalvfs)
@MonkeyClass(hostdev, '_pci_header_type', lambda _: 0)
class HostdevCreationTests(XMLTestCase):
_PCI_ADDRESS = {'slot': '0x02', 'bus': '0x01', 'domain': '0x0000',
'function': '0x0', 'type': 'pci'}
_PCI_ADDRESS_XML = '<address bus="0x01" domain="0x0000" function="0x0" \
slot="0x02" type="pci"/>'
def setUp(self):
self.conf = {
'vmName': 'testVm',
'vmId': '9ffe28b6-6134-4b1e-8804-1185f49c436f',
'smp': '8', 'maxVCpus': '160',
'memSize': '1024', 'memGuaranteedSize': '512'}
# TODO: next 2 tests should reside in their own module (interfaceTests.py)
def testCreateSRIOVVF(self):
dev_spec = {'type': hwclass.NIC, 'device': 'hostdev',
'hostdev': hostdevlib.SRIOV_VF,
'macAddr': 'ff:ff:ff:ff:ff:ff',
'specParams': {'vlanid': 3},
'bootOrder': '9'}
device = network.Interface(self.log, **dev_spec)
self.assertXMLEqual(
xmlutils.tostring(device.getXML()),
hostdevlib.DEVICE_XML[hostdevlib.SRIOV_VF] % ('',))
def testCreateSRIOVVFWithAddress(self):
dev_spec = {'type': hwclass.NIC, 'device': 'hostdev',
'hostdev': hostdevlib.SRIOV_VF,
'macAddr': 'ff:ff:ff:ff:ff:ff',
'specParams': {'vlanid': 3},
'bootOrder': '9', 'address':
{'slot': '0x02', 'bus': '0x01', 'domain': '0x0000',
'function': '0x0', 'type': 'pci'}}
device = network.Interface(self.log, **dev_spec)
self.assertXMLEqual(
xmlutils.tostring(device.getXML()),
hostdevlib.DEVICE_XML[hostdevlib.SRIOV_VF] % (
self._PCI_ADDRESS_XML
)
)
@expandPermutations
@MonkeyClass(hostdev, '_each_supported_mdev_type', hostdevlib.fake_mdev_types)
@MonkeyClass(hostdev, '_mdev_type_details', hostdevlib.fake_mdev_details)
@MonkeyClass(hostdev, '_mdev_device_vendor', hostdevlib.fake_mdev_vendor)
@MonkeyClass(hostdev, '_mdev_type_devices', hostdevlib.fake_mdev_instances)
@MonkeyClass(hostdev, 'supervdsm', hostdevlib.FakeSuperVdsm())
class TestMdev(TestCaseBase):
def setUp(self):
def make_device(name):
mdev_types = [
hostdevlib.FakeMdevType('incompatible-1', 2),
hostdevlib.FakeMdevType('8q', 1),
hostdevlib.FakeMdevType('4q', 2),
hostdevlib.FakeMdevType('incompatible-2', 2),
]
return hostdevlib.FakeMdevDevice(name=name, vendor='0x10de',
mdev_types=mdev_types)
self.devices = [make_device(name) for name in ('card-1', 'card-2',)]
@permutations([
# (mdev_type, mdev_uuid)*, mdev_placement, instances
[[('4q', '4q-1')],
hostdev.MdevPlacement.COMPACT, [['4q-1'], []]],
[[('8q', '8q-1')],
hostdev.MdevPlacement.SEPARATE, [['8q-1'], []]],
[[('4q', '4q-1'), ('4q', '4q-2')],
hostdev.MdevPlacement.COMPACT, [['4q-1', '4q-2'], []]],
[[('4q', '4q-1'), ('8q', '8q-1')],
hostdev.MdevPlacement.COMPACT, [['4q-1'], ['8q-1']]],
[[('4q', '4q-1'), ('4q', '4q-2')],
hostdev.MdevPlacement.SEPARATE, [['4q-1'], ['4q-2']]],
[[('4q', '4q-1'), ('8q', '8q-1'), ('4q', '4q-2')],
hostdev.MdevPlacement.COMPACT, [['4q-1', '4q-2'], ['8q-1']]],
[[('8q', '8q-1'), ('4q', '4q-1'), ('4q', '4q-2')],
hostdev.MdevPlacement.COMPACT, [['8q-1'], ['4q-1', '4q-2']]],
[[('4q', '4q-1'), ('4q', '4q-2'), ('8q', '8q-1')],
hostdev.MdevPlacement.COMPACT, [['4q-1', '4q-2'], ['8q-1']]],
[[('4q', '4q-1'), ('8q', '8q-1'), ('4q', '4q-2')],
hostdev.MdevPlacement.SEPARATE, [['4q-1', '4q-2'], ['8q-1']]],
])
def test_vgpu_placement(self, mdev_specs, mdev_placement, instances):
with MonkeyPatchScope([
(hostdev, '_each_mdev_device', lambda: self.devices)
]):
for mdev_type, mdev_uuid in mdev_specs:
hostdev.spawn_mdev(mdev_type, mdev_uuid, mdev_placement,
self.log)
for inst, dev in zip(instances, self.devices):
dev_inst = []
for mdev_type in dev.mdev_types:
dev_inst.extend(mdev_type.instances)
self.assertEqual(inst, dev_inst)
@permutations([
[hostdev.MdevPlacement.COMPACT],
[hostdev.MdevPlacement.SEPARATE],
])
def test_unsupported_vgpu_placement(self, placement):
with MonkeyPatchScope([
(hostdev, '_each_mdev_device', lambda: self.devices)
]):
self.assertRaises(
exception.ResourceUnavailable,
hostdev.spawn_mdev, 'unsupported', '1234', placement, self.log
)