Skip to content

Commit 458b443

Browse files
committed
libvirt: Fix regression of listDevices() return type
This a partial revert of change I60d6f04d374e9ede5895a43b7a75e955b0fea3c5 which added tpool.Proxy wrapping to the listDevices() and listAllDevices() methods. The regression was caught during downstream testing with vGPUs and the update_available_resource() periodic task was failing with: TypeError: virNodeDeviceLookupByName() argument 2 must be str or None, not Proxy It turns out that while the listAllDevices() method returns a list of virNodeDevice objects [1], the listDevices() method returns a list of string names [2] and is generated from the corresponding function in C [3]. The error was not caught by unit or functional testing because those test environments intentionally do not import the libvirt Python module -- so mocked code in the LibvirtFixture runs instead. Also, the update_available_resource() method has a 'except Exception:' at the end which logs an error but does not re-raise. So it would not cause a functional test to fail. This reverts the change that caused the regression, updates potentially confusing docstrings, adds type annotations to the methods that use listDevices(), and moves the nodeDeviceLookupByName type checking into the LibvirtFixture. Closes-Bug: #2098892 [1] https://github.com/libvirt/libvirt-python/blob/408815a/libvirt-override-virConnect.py#L520-L524 [2] https://github.com/libvirt/libvirt-python/blob/408815a/libvirt-override-api.xml#L448-L453 [3] https://libvirt.org/html/libvirt-libvirt-nodedev.html#virNodeListDevices Change-Id: Ib5befdd3c13367daa208ff969f66cba693ae2c76 (cherry picked from commit 2c07aa0) (cherry picked from commit c4f4ae7) (cherry picked from commit b8bfa1e) (cherry picked from commit c446736)
1 parent a5e0048 commit 458b443

File tree

4 files changed

+33
-91
lines changed

4 files changed

+33
-91
lines changed

nova/tests/fixtures/libvirt.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,17 @@ def device_lookup_by_name(self, dev_name):
20672067
return self.pci_info.get_device_by_name(dev_name)
20682068

20692069
def nodeDeviceLookupByName(self, name):
2070+
# See bug https://bugs.launchpad.net/nova/+bug/2098892
2071+
# We don't test this by importing the libvirt module because the
2072+
# libvirt module is forbidden to be imported into our test
2073+
# environment. It is excluded from test-requirements.txt and we
2074+
# also use the ImportModulePoisonFixture in nova/test.py to prevent
2075+
# use of modules such as libvirt.
2076+
if not isinstance(name, str) and name is not None:
2077+
raise TypeError(
2078+
'virNodeDeviceLookupByName() argument 2 must be str or '
2079+
f'None, not {type(name)}')
2080+
20702081
if name.startswith('mdev'):
20712082
return self.mdev_info.get_device_by_name(name)
20722083

nova/tests/functional/regressions/test_bug_2098892.py

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
# License for the specific language governing permissions and limitations
1111
# under the License.
1212

13-
from nova import test
1413
from nova.tests.fixtures import libvirt as fakelibvirt
1514
from nova.tests.functional.libvirt import test_vgpu
1615

@@ -47,73 +46,7 @@ def setUp(self):
4746

4847
self.start_compute_with_vgpu('host1')
4948

50-
def fake_nodeDeviceLookupByName(self, name):
51-
# See bug https://bugs.launchpad.net/nova/+bug/2098892
52-
# We don't test this by importing the libvirt module because the
53-
# libvirt module is forbidden to be imported into our test
54-
# environment. It is excluded from test-requirements.txt and we
55-
# also use the ImportModulePoisonFixture in nova/test.py to prevent
56-
# use of modules such as libvirt.
57-
if not isinstance(name, str) and name is not None:
58-
raise TypeError(
59-
'virNodeDeviceLookupByName() argument 2 must be str or '
60-
f'None, not {type(name)}')
61-
62-
# FIXME(melwitt): We need to patch this only for this test because if
63-
# we add it to the LibvirtFixture right away, it will cause the
64-
# following additional tests to fail:
65-
#
66-
# nova.tests.functional.libvirt.test_reshape.VGPUReshapeTests
67-
# test_create_servers_with_vgpu
68-
#
69-
# nova.tests.functional.libvirt.test_vgpu.DifferentMdevClassesTests
70-
# test_create_servers_with_different_mdev_classes
71-
# test_resize_servers_with_mlx5
72-
#
73-
# nova.tests.functional.libvirt.test_vgpu.VGPULimitMultipleTypesTests
74-
# test_create_servers_with_vgpu
75-
#
76-
# nova.tests.functional.libvirt.test_vgpu.VGPULiveMigrationTests
77-
# test_live_migrate_server
78-
# test_live_migration_fails_on_old_source
79-
# test_live_migration_fails_due_to_non_supported_mdev_types
80-
# test_live_migration_fails_on_old_destination
81-
#
82-
# nova.tests.functional.libvirt.
83-
# test_vgpu.VGPULiveMigrationTestsLMFailed
84-
# test_live_migrate_server
85-
# test_live_migration_fails_on_old_source
86-
# test_live_migration_fails_due_to_non_supported_mdev_types
87-
# test_live_migration_fails_on_old_destination
88-
#
89-
# nova.tests.functional.libvirt.test_vgpu.VGPUMultipleTypesTests
90-
# test_create_servers_with_specific_type
91-
# test_create_servers_with_vgpu
92-
#
93-
# nova.tests.functional.libvirt.test_vgpu.VGPUTests
94-
# test_multiple_instance_create
95-
# test_create_servers_with_vgpu
96-
# test_create_server_with_two_vgpus_isolated
97-
# test_resize_servers_with_vgpu
98-
#
99-
# nova.tests.functional.libvirt.test_vgpu.VGPUTestsLibvirt7_3
100-
# test_create_servers_with_vgpu
101-
# test_create_server_with_two_vgpus_isolated
102-
# test_resize_servers_with_vgpu
103-
# test_multiple_instance_create
104-
#
105-
# nova.tests.functional.regressions.
106-
# test_bug_1951656.VGPUTestsLibvirt7_7
107-
# test_create_servers_with_vgpu
108-
self.stub_out(
109-
'nova.tests.fixtures.libvirt.Connection.nodeDeviceLookupByName',
110-
fake_nodeDeviceLookupByName)
111-
11249
def test_update_available_resource(self):
11350
# We only want to verify no errors were logged by
11451
# update_available_resource (logging under the 'except Exception:').
115-
# FIXME(melwitt): This currently will log an error and traceback
116-
# because of the bug. Update this when the bug is fixed.
117-
e = self.assertRaises(
118-
test.TestingException, self._run_periodics, raise_on_error=True)
119-
self.assertIn('TypeError', str(e))
52+
self._run_periodics(raise_on_error=True)

nova/tests/unit/virt/libvirt/test_host.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,24 +2175,24 @@ def test_tpool_list_all_devices(self):
21752175

21762176
def test_tpool_list_pci_devices(self):
21772177
self._add_fake_host_devices()
2178-
devs = self.host.list_pci_devices()
2179-
self.assertEqual(8, len(devs))
2180-
for dev in devs:
2181-
self.assertIsInstance(dev, tpool.Proxy)
2178+
dev_names = self.host.list_pci_devices()
2179+
self.assertEqual(8, len(dev_names))
2180+
for name in dev_names:
2181+
self.assertIsInstance(name, str)
21822182

21832183
def test_tpool_list_mdev_capable_devices(self):
21842184
self._add_fake_host_devices()
2185-
devs = self.host.list_mdev_capable_devices()
2186-
self.assertEqual(3, len(devs))
2187-
for dev in devs:
2188-
self.assertIsInstance(dev, tpool.Proxy)
2185+
dev_names = self.host.list_mdev_capable_devices()
2186+
self.assertEqual(3, len(dev_names))
2187+
for name in dev_names:
2188+
self.assertIsInstance(name, str)
21892189

21902190
def test_tpool_list_mediated_devices(self):
21912191
self._add_fake_host_devices()
2192-
devs = self.host.list_mediated_devices()
2193-
self.assertEqual(1, len(devs))
2194-
for dev in devs:
2195-
self.assertIsInstance(dev, tpool.Proxy)
2192+
dev_names = self.host.list_mediated_devices()
2193+
self.assertEqual(1, len(dev_names))
2194+
for name in dev_names:
2195+
self.assertIsInstance(name, str)
21962196

21972197

21982198
class LoadersTestCase(test.NoDBTestCase):

nova/virt/libvirt/host.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,36 +1565,34 @@ def get_vdpa_device_path(
15651565
nodedev = self.get_vdpa_nodedev_by_address(pci_address)
15661566
return nodedev.vdpa_capability.dev_path
15671567

1568-
def list_pci_devices(self, flags=0):
1568+
def list_pci_devices(self, flags: int = 0) -> ty.List[str]:
15691569
"""Lookup pci devices.
15701570
1571-
:returns: a list of virNodeDevice instance
1571+
:returns: a list of strings, names of the virNodeDevice instances
15721572
"""
15731573
return self._list_devices("pci", flags=flags)
15741574

1575-
def list_mdev_capable_devices(self, flags=0):
1575+
def list_mdev_capable_devices(self, flags: int = 0) -> ty.List[str]:
15761576
"""Lookup devices supporting mdev capabilities.
15771577
1578-
:returns: a list of virNodeDevice instance
1578+
:returns: a list of strings, names of the virNodeDevice instances
15791579
"""
15801580
return self._list_devices("mdev_types", flags=flags)
15811581

1582-
def list_mediated_devices(self, flags=0):
1582+
def list_mediated_devices(self, flags: int = 0) -> ty.List[str]:
15831583
"""Lookup mediated devices.
15841584
1585-
:returns: a list of strings with the name of the instance
1585+
:returns: a list of strings, names of the virNodeDevice instances
15861586
"""
15871587
return self._list_devices("mdev", flags=flags)
15881588

1589-
def _list_devices(self, cap, flags=0):
1589+
def _list_devices(self, cap, flags: int = 0) -> ty.List[str]:
15901590
"""Lookup devices.
15911591
1592-
:returns: a list of virNodeDevice instance
1592+
:returns: a list of strings, names of the virNodeDevice instances
15931593
"""
15941594
try:
1595-
devs = [self._wrap_libvirt_proxy(dev)
1596-
for dev in self.get_connection().listDevices(cap, flags)]
1597-
return devs
1595+
return self.get_connection().listDevices(cap, flags)
15981596
except libvirt.libvirtError as ex:
15991597
error_code = ex.get_error_code()
16001598
if error_code == libvirt.VIR_ERR_NO_SUPPORT:

0 commit comments

Comments
 (0)