diff options
author | Zuul <zuul@review.opendev.org> | 2023-05-17 23:20:34 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2023-05-17 23:20:34 +0000 |
commit | 2c8772ab51352555726227b99ae3b84b586627c6 (patch) | |
tree | e8d7731af4d4b314dda90bec11db114a0d4f0b67 | |
parent | 217e21aacf3e28aa47098d44451cbe077b64206d (diff) | |
parent | bdc32226e2d9ce4a073306f8f6267fbe305e64e4 (diff) | |
download | nova-2c8772ab51352555726227b99ae3b84b586627c6.tar.gz |
Merge "Reproducer for bug 1983753" into stable/yoga
-rw-r--r-- | nova/tests/functional/regressions/test_bug_1983753.py | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/nova/tests/functional/regressions/test_bug_1983753.py b/nova/tests/functional/regressions/test_bug_1983753.py new file mode 100644 index 0000000000..a11ea8dc63 --- /dev/null +++ b/nova/tests/functional/regressions/test_bug_1983753.py @@ -0,0 +1,193 @@ +# 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 fixtures + +from oslo_serialization import jsonutils + +from nova.tests.fixtures import libvirt as fakelibvirt +from nova.tests.functional.api import client +from nova.tests.functional.libvirt import test_pci_sriov_servers + + +class TestPciResize(test_pci_sriov_servers._PCIServersTestBase): + # these tests use multiple different configs so the whitelist is set by + # each testcase individually + PCI_PASSTHROUGH_WHITELIST = [] + PCI_ALIAS = [ + jsonutils.dumps(x) + for x in [ + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.PCI_PROD_ID, + "name": "a-pci-dev", + }, + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.PF_PROD_ID, + "device_type": "type-PF", + "name": "a-pf", + }, + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.VF_PROD_ID, + "device_type": "type-VF", + "name": "a-vf", + }, + ] + ] + + def setUp(self): + super().setUp() + self.useFixture( + fixtures.MockPatch( + 'nova.virt.libvirt.driver.LibvirtDriver.' + 'migrate_disk_and_power_off', + return_value='{}' + ) + ) + # These tests should not depend on the host's sysfs + self.useFixture( + fixtures.MockPatch('nova.pci.utils.is_physical_function')) + self.useFixture( + fixtures.MockPatch( + 'nova.pci.utils.get_function_by_ifname', + return_value=(None, False) + ) + ) + + def _test_resize_from_two_devs_to_one_dev(self, num_pci_on_dest): + # The fake libvirt will emulate on the host: + # * two type-PCI in slot 0, 1 + compute1_pci_info = fakelibvirt.HostPCIDevicesInfo(num_pci=2) + # the config matches the PCI dev + compute1_device_spec = [ + jsonutils.dumps(x) + for x in [ + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.PCI_PROD_ID, + }, + ] + ] + self.flags(group='pci', passthrough_whitelist=compute1_device_spec) + self.start_compute(hostname="compute1", pci_info=compute1_pci_info) + self.assertPCIDeviceCounts("compute1", total=2, free=2) + + # create a server that requests two PCI devs + extra_spec = {"pci_passthrough:alias": "a-pci-dev:2"} + flavor_id = self._create_flavor(extra_spec=extra_spec) + server = self._create_server(flavor_id=flavor_id, networks=[]) + self.assertPCIDeviceCounts("compute1", total=2, free=0) + + # start another compute with a different amount of PCI dev available + compute2_pci_info = fakelibvirt.HostPCIDevicesInfo( + num_pci=num_pci_on_dest) + # the config matches the PCI dev + compute2_device_spec = [ + jsonutils.dumps(x) + for x in [ + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.PCI_PROD_ID, + }, + ] + ] + self.flags(group='pci', passthrough_whitelist=compute2_device_spec) + self.start_compute(hostname="compute2", pci_info=compute2_pci_info) + self.assertPCIDeviceCounts( + "compute2", total=num_pci_on_dest, free=num_pci_on_dest) + + # resize the server to request only one PCI dev instead of the current + # two. This should fit to compute2 having at least one dev + extra_spec = {"pci_passthrough:alias": "a-pci-dev:1"} + flavor_id = self._create_flavor(extra_spec=extra_spec) + self._resize_server(server, flavor_id=flavor_id) + self._confirm_resize(server) + self.assertPCIDeviceCounts("compute1", total=2, free=2) + self.assertPCIDeviceCounts( + "compute2", total=num_pci_on_dest, free=num_pci_on_dest - 1) + + def test_resize_from_two_devs_to_one_dev_dest_has_two_devs(self): + # this works + self._test_resize_from_two_devs_to_one_dev(num_pci_on_dest=2) + + def test_resize_from_two_devs_to_one_dev_dest_has_one_dev(self): + # This is bug 1983753 as nova uses the old InstancePciRequest during + # the scheduling and therefore tries to find a compute with two PCI + # devs even though the flavor only requests one. + ex = self.assertRaises( + client.OpenStackApiException, + self._test_resize_from_two_devs_to_one_dev, + num_pci_on_dest=1 + ) + self.assertIn('nova.exception.NoValidHost', str(ex)) + + def test_resize_from_vf_to_pf(self): + # The fake libvirt will emulate on the host: + # * one type-PF in slot 0 with one VF + compute1_pci_info = fakelibvirt.HostPCIDevicesInfo( + num_pfs=1, num_vfs=1) + # the config matches only the VF + compute1_device_spec = [ + jsonutils.dumps(x) + for x in [ + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.VF_PROD_ID, + }, + ] + ] + self.flags(group='pci', passthrough_whitelist=compute1_device_spec) + self.start_compute(hostname="compute1", pci_info=compute1_pci_info) + self.assertPCIDeviceCounts("compute1", total=1, free=1) + + # create a server that requests one Vf + extra_spec = {"pci_passthrough:alias": "a-vf:1"} + flavor_id = self._create_flavor(extra_spec=extra_spec) + server = self._create_server(flavor_id=flavor_id, networks=[]) + self.assertPCIDeviceCounts("compute1", total=1, free=0) + + # start another compute with a single PF dev available + # The fake libvirt will emulate on the host: + # * one type-PF in slot 0 with 1 VF + compute2_pci_info = fakelibvirt.HostPCIDevicesInfo( + num_pfs=1, num_vfs=1) + # the config matches the PF dev but not the VF + compute2_device_spec = [ + jsonutils.dumps(x) + for x in [ + { + "vendor_id": fakelibvirt.PCI_VEND_ID, + "product_id": fakelibvirt.PF_PROD_ID, + }, + ] + ] + self.flags(group='pci', passthrough_whitelist=compute2_device_spec) + self.start_compute(hostname="compute2", pci_info=compute2_pci_info) + self.assertPCIDeviceCounts("compute2", total=1, free=1) + + # resize the server to request on PF dev instead of the current VF + # dev. This should fit to compute2 having exactly one PF dev. + extra_spec = {"pci_passthrough:alias": "a-pf:1"} + flavor_id = self._create_flavor(extra_spec=extra_spec) + # This is bug 1983753 as nova uses the old InstancePciRequest during + # the scheduling and therefore tries to find a compute with a VF dev + # even though the flavor only requests a PF dev. + ex = self.assertRaises( + client.OpenStackApiException, + self._resize_server, + server, + flavor_id=flavor_id, + ) + self.assertIn('nova.exception.NoValidHost', str(ex)) |