From 07295b0f9944d316bfe8de25ecd659ced506433b Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Mon, 9 Sep 2024 11:09:32 +0200 Subject: [PATCH] [libvirt]Support hw_vif_model = igb Makes igb vif model supported for hosts with libvirt 9.3.0 and qemu 8.0.0 or higher. Implements: blueprint igb-vif-model Depends-On: https://review.opendev.org/c/openstack/os-traits/+/928582 (merged, released as 3.2.0) Change-Id: I6a1d8058c640e5dc015889610c4ae864ed9a5ccb --- .../functional/libvirt/test_vif_model.py | 97 +++++++++++++++++++ nova/tests/unit/virt/libvirt/test_driver.py | 22 ++++- nova/virt/libvirt/driver.py | 13 +++ nova/virt/libvirt/vif.py | 2 + .../bp-igb-vif-model-d1366bcbea7afdd2.yaml | 6 ++ requirements.txt | 2 +- 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 nova/tests/functional/libvirt/test_vif_model.py create mode 100644 releasenotes/notes/bp-igb-vif-model-d1366bcbea7afdd2.yaml diff --git a/nova/tests/functional/libvirt/test_vif_model.py b/nova/tests/functional/libvirt/test_vif_model.py new file mode 100644 index 000000000000..277842986ae5 --- /dev/null +++ b/nova/tests/functional/libvirt/test_vif_model.py @@ -0,0 +1,97 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import datetime + +from oslo_config import cfg +from oslo_utils.fixture import uuidsentinel as uuids + +import nova +from nova.tests.functional.libvirt import base + +CONF = cfg.CONF + + +class LibvirtVifModelTest(base.ServersTestBase): + ADMIN_API = True + + def setUp(self): + CONF.set_default("image_metadata_prefilter", True, group='scheduler') + super().setUp() + + self.glance.create( + None, + { + 'id': uuids.image_vif_model_igb, + 'name': 'image-with-igb', + 'created_at': datetime.datetime(2011, 1, 1, 1, 2, 3), + 'updated_at': datetime.datetime(2011, 1, 1, 1, 2, 3), + 'deleted_at': None, + 'deleted': False, + 'status': 'active', + 'is_public': False, + 'container_format': 'bare', + 'disk_format': 'qcow2', + 'size': '74185822', + 'min_ram': 0, + 'min_disk': 0, + 'protected': False, + 'visibility': 'public', + 'tags': [], + 'properties': { + 'hw_vif_model': 'igb', + }, + } + ) + + def test_boot_with_vif_model_igb(self): + orig_create = nova.virt.libvirt.guest.Guest.create + self.xml = "" + + def fake_create(cls, xml, host): + self.xml = xml + return orig_create(xml, host) + + self.stub_out('nova.virt.libvirt.guest.Guest.create', fake_create) + + self.start_compute( + hostname='compute1', + libvirt_version=9003000, + qemu_version=8000000, + ) + + self._create_server(image_uuid=uuids.image_vif_model_igb) + self.assertIn('', self.xml) + + def _test_boot_with_vif_model_igb_old_hypervisor( + self, libvirt_version, qemu_version + ): + self.start_compute( + hostname='compute1', + libvirt_version=libvirt_version, + qemu_version=qemu_version, + ) + + server = self._create_server( + image_uuid=uuids.image_vif_model_igb, expected_state='ERROR') + self.assertEqual( + "No valid host was found. ", server['fault']['message']) + + def test_boot_with_vif_model_igb_old_qemu(self): + self._test_boot_with_vif_model_igb_old_hypervisor( + libvirt_version=9003000, qemu_version=7000000) + + def test_boot_with_vif_model_igb_old_libvirt(self): + self._test_boot_with_vif_model_igb_old_hypervisor( + libvirt_version=9002000, qemu_version=8000000) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 1278a8ce9d2a..12d9cb2aa759 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -28186,7 +28186,9 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): bus_from_trait = trait.rsplit('_', 1)[1].lower() self.assertEqual(bus_from_trait in buses, bus_traits[trait]) - def test_vif_model_traits(self): + @mock.patch.object( + host.Host, 'has_min_version', return_value=True) + def test_vif_model_traits(self, mock_has_min_version): """Test getting vif model traits per virt type.""" for virt_type, models in libvirt_vif.SUPPORTED_VIF_MODELS.items(): self.flags(virt_type=virt_type, group='libvirt') @@ -28200,6 +28202,24 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): vif_models.pop(trait) self.assertTrue(all(not model for model in vif_models.values())) + mock_has_min_version.assert_called_with((9, 3, 0), (8, 0, 0)) + + @mock.patch.object( + host.Host, 'has_min_version', return_value=False) + def test_vif_model_traits_old_version_no_igb_support( + self, mock_has_min_version + ): + """Test getting vif model traits per virt type from old system not + supporting igb. + """ + for virt_type in ('qemu', 'kvm'): + models = libvirt_vif.SUPPORTED_VIF_MODELS[virt_type] + self.assertIn(network_model.VIF_MODEL_IGB, models) + vif_models = self.drvr._get_vif_model_traits() + self.assertFalse(vif_models['COMPUTE_NET_VIF_MODEL_IGB']) + + mock_has_min_version.assert_called_with((9, 3, 0), (8, 0, 0)) + def test_video_model_traits(self): """Test getting video model traits per virt type.""" # NOTE(sean-k-mooney): we do not have a static tables of which video diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index b718cdbe89fa..305def303410 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -260,6 +260,10 @@ MIN_QEMU_MAXPHYSADDR = (2, 7, 0) # stateless firmware support MIN_LIBVIRT_STATELESS_FIRMWARE = (8, 6, 0) +# Minimum versions supporting igb hw_vif_model +MIN_IGB_LIBVIRT_VERSION = (9, 3, 0) +MIN_IGB_QEMU_VERSION = (8, 0, 0) + REGISTER_IMAGE_PROPERTY_DEFAULTS = [ 'hw_machine_type', 'hw_cdrom_bus', @@ -12990,6 +12994,15 @@ class LibvirtDriver(driver.ComputeDriver): supported_models = libvirt_vif.SUPPORTED_VIF_MODELS.get( CONF.libvirt.virt_type, [] ) + + # remove version dependent vif models if we are on older libvirt/qemu + igb_supported = self._host.has_min_version( + MIN_IGB_LIBVIRT_VERSION, MIN_IGB_QEMU_VERSION) + if not igb_supported: + supported_models = [ + model for model in supported_models + if model != network_model.VIF_MODEL_IGB] + # construct the corresponding standard trait from the VIF model name return { f'COMPUTE_NET_VIF_MODEL_{model.replace("-", "_").upper()}': model diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 6e9069fa50ff..275cb002af06 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -61,6 +61,7 @@ SUPPORTED_VIF_MODELS = { network_model.VIF_MODEL_LAN9118, network_model.VIF_MODEL_SPAPR_VLAN, network_model.VIF_MODEL_VMXNET3, + network_model.VIF_MODEL_IGB, ], 'kvm': [ network_model.VIF_MODEL_VIRTIO, @@ -71,6 +72,7 @@ SUPPORTED_VIF_MODELS = { network_model.VIF_MODEL_E1000E, network_model.VIF_MODEL_SPAPR_VLAN, network_model.VIF_MODEL_VMXNET3, + network_model.VIF_MODEL_IGB, ], 'lxc': [], 'parallels': [ diff --git a/releasenotes/notes/bp-igb-vif-model-d1366bcbea7afdd2.yaml b/releasenotes/notes/bp-igb-vif-model-d1366bcbea7afdd2.yaml new file mode 100644 index 000000000000..144457cc12c4 --- /dev/null +++ b/releasenotes/notes/bp-igb-vif-model-d1366bcbea7afdd2.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The libvirt driver now supports hw_vif_model=igb image property + if the hypervisor has libvirt version 9.3.0 and qemu version 8.0.0 + or higher. diff --git a/requirements.txt b/requirements.txt index ee99fa57d419..36d5026fec89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -52,7 +52,7 @@ psutil>=3.2.2 # BSD oslo.versionedobjects>=1.35.0 # Apache-2.0 os-brick>=6.0 # Apache-2.0 os-resource-classes>=1.1.0 # Apache-2.0 -os-traits>=3.1.0 # Apache-2.0 +os-traits>=3.2.0 # Apache-2.0 os-vif>=3.1.0 # Apache-2.0 castellan>=0.16.0 # Apache-2.0 microversion-parse>=0.2.1 # Apache-2.0