Skip to content

Commit 8fb6811

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Reproducer for bug 1983753" into stable/wallaby
2 parents ae3addd + 81741d7 commit 8fb6811

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
import fixtures
15+
16+
from oslo_serialization import jsonutils
17+
18+
from nova.tests.functional.api import client
19+
from nova.tests.functional.libvirt import test_pci_sriov_servers
20+
from nova.tests.unit.virt.libvirt import fakelibvirt
21+
22+
23+
class TestPciResize(test_pci_sriov_servers._PCIServersTestBase):
24+
# these tests use multiple different configs so the whitelist is set by
25+
# each testcase individually
26+
PCI_PASSTHROUGH_WHITELIST = []
27+
PCI_ALIAS = [
28+
jsonutils.dumps(x)
29+
for x in [
30+
{
31+
"vendor_id": fakelibvirt.PCI_VEND_ID,
32+
"product_id": fakelibvirt.PCI_PROD_ID,
33+
"name": "a-pci-dev",
34+
},
35+
{
36+
"vendor_id": fakelibvirt.PCI_VEND_ID,
37+
"product_id": fakelibvirt.PF_PROD_ID,
38+
"device_type": "type-PF",
39+
"name": "a-pf",
40+
},
41+
{
42+
"vendor_id": fakelibvirt.PCI_VEND_ID,
43+
"product_id": fakelibvirt.VF_PROD_ID,
44+
"device_type": "type-VF",
45+
"name": "a-vf",
46+
},
47+
]
48+
]
49+
50+
def setUp(self):
51+
super().setUp()
52+
self.useFixture(
53+
fixtures.MockPatch(
54+
'nova.virt.libvirt.driver.LibvirtDriver.'
55+
'migrate_disk_and_power_off',
56+
return_value='{}'
57+
)
58+
)
59+
# These tests should not depend on the host's sysfs
60+
self.useFixture(
61+
fixtures.MockPatch('nova.pci.utils.is_physical_function'))
62+
self.useFixture(
63+
fixtures.MockPatch(
64+
'nova.pci.utils.get_function_by_ifname',
65+
return_value=(None, False)
66+
)
67+
)
68+
69+
def _test_resize_from_two_devs_to_one_dev(self, num_pci_on_dest):
70+
# The fake libvirt will emulate on the host:
71+
# * two type-PCI in slot 0, 1
72+
compute1_pci_info = fakelibvirt.HostPCIDevicesInfo(num_pci=2)
73+
# the config matches the PCI dev
74+
compute1_device_spec = [
75+
jsonutils.dumps(x)
76+
for x in [
77+
{
78+
"vendor_id": fakelibvirt.PCI_VEND_ID,
79+
"product_id": fakelibvirt.PCI_PROD_ID,
80+
},
81+
]
82+
]
83+
self.flags(group='pci', passthrough_whitelist=compute1_device_spec)
84+
self.start_compute(hostname="compute1", pci_info=compute1_pci_info)
85+
self.assertPCIDeviceCounts("compute1", total=2, free=2)
86+
87+
# create a server that requests two PCI devs
88+
extra_spec = {"pci_passthrough:alias": "a-pci-dev:2"}
89+
flavor_id = self._create_flavor(extra_spec=extra_spec)
90+
server = self._create_server(flavor_id=flavor_id, networks=[])
91+
self.assertPCIDeviceCounts("compute1", total=2, free=0)
92+
93+
# start another compute with a different amount of PCI dev available
94+
compute2_pci_info = fakelibvirt.HostPCIDevicesInfo(
95+
num_pci=num_pci_on_dest)
96+
# the config matches the PCI dev
97+
compute2_device_spec = [
98+
jsonutils.dumps(x)
99+
for x in [
100+
{
101+
"vendor_id": fakelibvirt.PCI_VEND_ID,
102+
"product_id": fakelibvirt.PCI_PROD_ID,
103+
},
104+
]
105+
]
106+
self.flags(group='pci', passthrough_whitelist=compute2_device_spec)
107+
self.start_compute(hostname="compute2", pci_info=compute2_pci_info)
108+
self.assertPCIDeviceCounts(
109+
"compute2", total=num_pci_on_dest, free=num_pci_on_dest)
110+
111+
# resize the server to request only one PCI dev instead of the current
112+
# two. This should fit to compute2 having at least one dev
113+
extra_spec = {"pci_passthrough:alias": "a-pci-dev:1"}
114+
flavor_id = self._create_flavor(extra_spec=extra_spec)
115+
self._resize_server(server, flavor_id=flavor_id)
116+
self._confirm_resize(server)
117+
self.assertPCIDeviceCounts("compute1", total=2, free=2)
118+
self.assertPCIDeviceCounts(
119+
"compute2", total=num_pci_on_dest, free=num_pci_on_dest - 1)
120+
121+
def test_resize_from_two_devs_to_one_dev_dest_has_two_devs(self):
122+
# this works
123+
self._test_resize_from_two_devs_to_one_dev(num_pci_on_dest=2)
124+
125+
def test_resize_from_two_devs_to_one_dev_dest_has_one_dev(self):
126+
# This is bug 1983753 as nova uses the old InstancePciRequest during
127+
# the scheduling and therefore tries to find a compute with two PCI
128+
# devs even though the flavor only requests one.
129+
ex = self.assertRaises(
130+
client.OpenStackApiException,
131+
self._test_resize_from_two_devs_to_one_dev,
132+
num_pci_on_dest=1
133+
)
134+
self.assertIn('nova.exception.NoValidHost', str(ex))
135+
136+
def test_resize_from_vf_to_pf(self):
137+
# The fake libvirt will emulate on the host:
138+
# * one type-PF in slot 0 with one VF
139+
compute1_pci_info = fakelibvirt.HostPCIDevicesInfo(
140+
num_pfs=1, num_vfs=1)
141+
# the config matches only the VF
142+
compute1_device_spec = [
143+
jsonutils.dumps(x)
144+
for x in [
145+
{
146+
"vendor_id": fakelibvirt.PCI_VEND_ID,
147+
"product_id": fakelibvirt.VF_PROD_ID,
148+
},
149+
]
150+
]
151+
self.flags(group='pci', passthrough_whitelist=compute1_device_spec)
152+
self.start_compute(hostname="compute1", pci_info=compute1_pci_info)
153+
self.assertPCIDeviceCounts("compute1", total=1, free=1)
154+
155+
# create a server that requests one Vf
156+
extra_spec = {"pci_passthrough:alias": "a-vf:1"}
157+
flavor_id = self._create_flavor(extra_spec=extra_spec)
158+
server = self._create_server(flavor_id=flavor_id, networks=[])
159+
self.assertPCIDeviceCounts("compute1", total=1, free=0)
160+
161+
# start another compute with a single PF dev available
162+
# The fake libvirt will emulate on the host:
163+
# * one type-PF in slot 0 with 1 VF
164+
compute2_pci_info = fakelibvirt.HostPCIDevicesInfo(
165+
num_pfs=1, num_vfs=1)
166+
# the config matches the PF dev but not the VF
167+
compute2_device_spec = [
168+
jsonutils.dumps(x)
169+
for x in [
170+
{
171+
"vendor_id": fakelibvirt.PCI_VEND_ID,
172+
"product_id": fakelibvirt.PF_PROD_ID,
173+
},
174+
]
175+
]
176+
self.flags(group='pci', passthrough_whitelist=compute2_device_spec)
177+
self.start_compute(hostname="compute2", pci_info=compute2_pci_info)
178+
self.assertPCIDeviceCounts("compute2", total=1, free=1)
179+
180+
# resize the server to request on PF dev instead of the current VF
181+
# dev. This should fit to compute2 having exactly one PF dev.
182+
extra_spec = {"pci_passthrough:alias": "a-pf:1"}
183+
flavor_id = self._create_flavor(extra_spec=extra_spec)
184+
# This is bug 1983753 as nova uses the old InstancePciRequest during
185+
# the scheduling and therefore tries to find a compute with a VF dev
186+
# even though the flavor only requests a PF dev.
187+
ex = self.assertRaises(
188+
client.OpenStackApiException,
189+
self._resize_server,
190+
server,
191+
flavor_id=flavor_id,
192+
)
193+
self.assertIn('nova.exception.NoValidHost', str(ex))

0 commit comments

Comments
 (0)