summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2023-05-17 23:20:34 +0000
committerGerrit Code Review <review@openstack.org>2023-05-17 23:20:34 +0000
commit2c8772ab51352555726227b99ae3b84b586627c6 (patch)
treee8d7731af4d4b314dda90bec11db114a0d4f0b67
parent217e21aacf3e28aa47098d44451cbe077b64206d (diff)
parentbdc32226e2d9ce4a073306f8f6267fbe305e64e4 (diff)
downloadnova-2c8772ab51352555726227b99ae3b84b586627c6.tar.gz
Merge "Reproducer for bug 1983753" into stable/yoga
-rw-r--r--nova/tests/functional/regressions/test_bug_1983753.py193
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))