Skip to content

Commit afc55c5

Browse files
gibizerSeanMooney
authored andcommitted
Add compute restart capability for libvirt func tests
The existing generic restart_compute_service() call in the nova test base class is not appropriate for the libvirt functional test that needs to reconfigure the libvirt connection as it is not aware of the libvirt specific mocking needed when a compute service is started. So this patch adds a specific restart_compute_service() call to nova.tests.functional.libvirt.base.ServersTestBase. This will be used by a later patch testing [pci]device_spec reconfiguration scenarios. This change showed that some of the existing libvirt functional test used the incomplete restart_compute_service from the base class. Others used local mocking to inject new pci config to the restart. I moved all these to the new function and removed the local mocking. Conflicts: nova/tests/functional/libvirt/test_device_bus_migration.py Change-Id: Ic717dc42ac6b6cace59d344acaf12f9d1ee35564 (cherry picked from commit 57c253a) (cherry picked from commit f98858a)
1 parent b36bc92 commit afc55c5

File tree

6 files changed

+123
-50
lines changed

6 files changed

+123
-50
lines changed

nova/tests/functional/libvirt/base.py

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def _get_connection(
114114
def start_compute(
115115
self, hostname='compute1', host_info=None, pci_info=None,
116116
mdev_info=None, vdpa_info=None, libvirt_version=None,
117-
qemu_version=None,
117+
qemu_version=None, cell_name=None, connection=None
118118
):
119119
"""Start a compute service.
120120
@@ -124,16 +124,35 @@ def start_compute(
124124
:param host_info: A fakelibvirt.HostInfo object for the host. Defaults
125125
to a HostInfo with 2 NUMA nodes, 2 cores per node, 2 threads per
126126
core, and 16GB of RAM.
127+
:param connection: A fake libvirt connection. You should not provide it
128+
directly. However it is used by restart_compute_service to
129+
implement restart without loosing the hypervisor state.
127130
:returns: The hostname of the created service, which can be used to
128131
lookup the created service and UUID of the assocaited resource
129132
provider.
130133
"""
134+
if connection and (
135+
host_info or
136+
pci_info or
137+
mdev_info or
138+
vdpa_info or
139+
libvirt_version or
140+
qemu_version
141+
):
142+
raise ValueError(
143+
"Either an existing connection instance can be provided or a "
144+
"list of parameters for a new connection"
145+
)
131146

132147
def _start_compute(hostname, host_info):
133-
fake_connection = self._get_connection(
134-
host_info, pci_info, mdev_info, vdpa_info, libvirt_version,
135-
qemu_version, hostname,
136-
)
148+
if connection:
149+
fake_connection = connection
150+
else:
151+
fake_connection = self._get_connection(
152+
host_info, pci_info, mdev_info, vdpa_info, libvirt_version,
153+
qemu_version, hostname,
154+
)
155+
137156
# If the compute is configured with PCI devices then we need to
138157
# make sure that the stubs around sysfs has the MAC address
139158
# information for the PCI PF devices
@@ -144,7 +163,8 @@ def _start_compute(hostname, host_info):
144163
# actually start the service.
145164
orig_con = self.mock_conn.return_value
146165
self.mock_conn.return_value = fake_connection
147-
compute = self.start_service('compute', host=hostname)
166+
compute = self.start_service(
167+
'compute', host=hostname, cell_name=cell_name)
148168
# Once that's done, we need to tweak the compute "service" to
149169
# make sure it returns unique objects.
150170
compute.driver._host.get_connection = lambda: fake_connection
@@ -165,6 +185,74 @@ def _start_compute(hostname, host_info):
165185

166186
return hostname
167187

188+
def restart_compute_service(
189+
self,
190+
hostname,
191+
host_info=None,
192+
pci_info=None,
193+
mdev_info=None,
194+
vdpa_info=None,
195+
libvirt_version=None,
196+
qemu_version=None,
197+
keep_hypervisor_state=True,
198+
):
199+
"""Stops the service and starts a new one to have realistic restart
200+
201+
:param hostname: the hostname of the nova-compute service to be
202+
restarted
203+
:param keep_hypervisor_state: If True then we reuse the fake connection
204+
from the existing driver. If False a new connection will be created
205+
based on the other parameters provided
206+
"""
207+
# We are intentionally not calling super() here. Nova's base test class
208+
# defines starting and restarting compute service with a very
209+
# different signatures and also those calls are cannot be made aware of
210+
# the intricacies of the libvirt fixture. So we simply hide that
211+
# implementation.
212+
213+
if keep_hypervisor_state and (
214+
host_info or
215+
pci_info or
216+
mdev_info or
217+
vdpa_info or
218+
libvirt_version or
219+
qemu_version
220+
):
221+
raise ValueError(
222+
"Either keep_hypervisor_state=True or a list of libvirt "
223+
"parameters can be provided but not both"
224+
)
225+
226+
compute = self.computes.pop(hostname)
227+
self.compute_rp_uuids.pop(hostname)
228+
229+
# NOTE(gibi): The service interface cannot be used to simulate a real
230+
# service restart as the manager object will not be recreated after a
231+
# service.stop() and service.start() therefore the manager state will
232+
# survive. For example the resource tracker will not be recreated after
233+
# a stop start. The service.kill() call cannot help as it deletes
234+
# the service from the DB which is unrealistic and causes that some
235+
# operation that refers to the killed host (e.g. evacuate) fails.
236+
# So this helper method will stop the original service and then starts
237+
# a brand new compute service for the same host and node. This way
238+
# a new ComputeManager instance will be created and initialized during
239+
# the service startup.
240+
compute.stop()
241+
242+
# this service was running previously, so we have to make sure that
243+
# we restart it in the same cell
244+
cell_name = self.host_mappings[compute.host].cell_mapping.name
245+
246+
old_connection = compute.manager.driver._get_connection()
247+
248+
self.start_compute(
249+
hostname, host_info, pci_info, mdev_info, vdpa_info,
250+
libvirt_version, qemu_version, cell_name,
251+
old_connection if keep_hypervisor_state else None
252+
)
253+
254+
return self.computes[hostname]
255+
168256

169257
class LibvirtMigrationMixin(object):
170258
"""A simple mixin to facilliate successful libvirt live migrations

nova/tests/functional/libvirt/test_numa_live_migration.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,8 @@ def _test(self, pin_dest):
206206
# Increase cpu_dedicated_set to 0-3, expecting the live migrated server
207207
# to end up on 2,3.
208208
self.flags(cpu_dedicated_set='0-3', group='compute')
209-
self.computes['host_a'] = self.restart_compute_service(
210-
self.computes['host_a'])
211-
self.computes['host_b'] = self.restart_compute_service(
212-
self.computes['host_b'])
209+
self.restart_compute_service('host_a')
210+
self.restart_compute_service('host_b')
213211

214212
# Live migrate, RPC-pinning the destination host if asked
215213
if pin_dest:
@@ -333,10 +331,8 @@ def _test(self, pin_dest=False):
333331
# Increase cpu_dedicated_set to 0-3, expecting the live migrated server
334332
# to end up on 2,3.
335333
self.flags(cpu_dedicated_set='0-3', group='compute')
336-
self.computes['host_a'] = self.restart_compute_service(
337-
self.computes['host_a'])
338-
self.computes['host_b'] = self.restart_compute_service(
339-
self.computes['host_b'])
334+
self.restart_compute_service('host_a')
335+
self.restart_compute_service('host_b')
340336

341337
# Live migrate, RPC-pinning the destination host if asked. This is a
342338
# rollback test, so server_a is expected to remain on host_a.

nova/tests/functional/libvirt/test_numa_servers.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,10 +1187,8 @@ def test_vcpu_to_pcpu_reshape(self):
11871187
self.flags(cpu_dedicated_set='0-7', group='compute')
11881188
self.flags(vcpu_pin_set=None)
11891189

1190-
computes = {}
1191-
for host, compute in self.computes.items():
1192-
computes[host] = self.restart_compute_service(compute)
1193-
self.computes = computes
1190+
for host in list(self.computes.keys()):
1191+
self.restart_compute_service(host)
11941192

11951193
# verify that the inventory, usages and allocation are correct after
11961194
# the reshape

nova/tests/functional/libvirt/test_pci_sriov_servers.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -907,11 +907,8 @@ def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
907907
# Disable SRIOV capabilties in PF and delete the VFs
908908
self._disable_sriov_in_pf(pci_info_no_sriov)
909909

910-
fake_connection = self._get_connection(pci_info=pci_info_no_sriov,
911-
hostname='test_compute0')
912-
self.mock_conn.return_value = fake_connection
913-
914-
self.compute = self.start_service('compute', host='test_compute0')
910+
self.start_compute('test_compute0', pci_info=pci_info_no_sriov)
911+
self.compute = self.computes['test_compute0']
915912

916913
ctxt = context.get_admin_context()
917914
pci_devices = objects.PciDeviceList.get_by_compute_node(
@@ -923,13 +920,9 @@ def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
923920
self.assertEqual(1, len(pci_devices))
924921
self.assertEqual('type-PCI', pci_devices[0].dev_type)
925922

926-
# Update connection with original pci info with sriov PFs
927-
fake_connection = self._get_connection(pci_info=pci_info,
928-
hostname='test_compute0')
929-
self.mock_conn.return_value = fake_connection
930-
931-
# Restart the compute service
932-
self.restart_compute_service(self.compute)
923+
# Restart the compute service with sriov PFs
924+
self.restart_compute_service(
925+
self.compute.host, pci_info=pci_info, keep_hypervisor_state=False)
933926

934927
# Verify if PCI devices are of type type-PF or type-VF
935928
pci_devices = objects.PciDeviceList.get_by_compute_node(
@@ -1014,10 +1007,9 @@ def _test_detach_attach(self, first_port_id, second_port_id):
10141007
host_info = fakelibvirt.HostInfo(cpu_nodes=2, cpu_sockets=1,
10151008
cpu_cores=2, cpu_threads=2)
10161009
pci_info = fakelibvirt.HostPCIDevicesInfo(num_pfs=1, num_vfs=1)
1017-
fake_connection = self._get_connection(host_info, pci_info)
1018-
self.mock_conn.return_value = fake_connection
1019-
1020-
self.compute = self.start_service('compute', host='test_compute0')
1010+
self.start_compute(
1011+
'test_compute0', host_info=host_info, pci_info=pci_info)
1012+
self.compute = self.computes['test_compute0']
10211013

10221014
# Create server with a port
10231015
server = self._create_server(networks=[{'port': first_port_id}])

nova/tests/functional/libvirt/test_reshape.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ def test_create_servers_with_vgpu(self):
7272
# ignore the content of the above HostMdevDeviceInfo
7373
self.flags(enabled_mdev_types='', group='devices')
7474

75-
hostname = self.start_compute(
75+
self.hostname = self.start_compute(
7676
hostname='compute1',
7777
mdev_info=fakelibvirt.HostMdevDevicesInfo(devices=mdevs),
7878
)
79-
self.compute = self.computes[hostname]
79+
self.compute = self.computes[self.hostname]
8080

8181
# create the VGPU resource in placement manually
8282
compute_rp_uuid = self.placement.get(
@@ -158,7 +158,7 @@ def test_create_servers_with_vgpu(self):
158158
allocations[compute_rp_uuid]['resources'])
159159

160160
# restart compute which will trigger a reshape
161-
self.compute = self.restart_compute_service(self.compute)
161+
self.compute = self.restart_compute_service(self.hostname)
162162

163163
# verify that the inventory, usages and allocation are correct after
164164
# the reshape

nova/tests/functional/libvirt/test_vgpu.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ def _create_mdev(self, physical_device, mdev_type, uuid=None):
113113
parent=libvirt_parent)})
114114
return uuid
115115

116-
def start_compute(self, hostname):
117-
hostname = super().start_compute(
116+
def start_compute_with_vgpu(self, hostname):
117+
hostname = self.start_compute(
118118
pci_info=fakelibvirt.HostPCIDevicesInfo(
119119
num_pci=0, num_pfs=0, num_vfs=0, num_mdevcap=2,
120120
),
@@ -197,7 +197,7 @@ def setUp(self):
197197
enabled_mdev_types=fakelibvirt.NVIDIA_11_VGPU_TYPE,
198198
group='devices')
199199

200-
self.compute1 = self.start_compute('host1')
200+
self.compute1 = self.start_compute_with_vgpu('host1')
201201

202202
def assert_vgpu_usage_for_compute(self, compute, expected):
203203
self.assert_mdev_usage(compute, expected_amount=expected)
@@ -211,7 +211,7 @@ def test_create_servers_with_vgpu(self):
211211

212212
def test_resize_servers_with_vgpu(self):
213213
# Add another compute for the sake of resizing
214-
self.compute2 = self.start_compute('host2')
214+
self.compute2 = self.start_compute_with_vgpu('host2')
215215
server = self._create_server(
216216
image_uuid='155d900f-4e14-4e4c-a73d-069cbf4541e6',
217217
flavor_id=self.flavor, host=self.compute1.host,
@@ -337,7 +337,7 @@ def setUp(self):
337337
# Prepare traits for later on
338338
self._create_trait('CUSTOM_NVIDIA_11')
339339
self._create_trait('CUSTOM_NVIDIA_12')
340-
self.compute1 = self.start_compute('host1')
340+
self.compute1 = self.start_compute_with_vgpu('host1')
341341

342342
def test_create_servers_with_vgpu(self):
343343
self._create_server(
@@ -369,13 +369,12 @@ def test_create_servers_with_vgpu(self):
369369

370370
def test_create_servers_with_specific_type(self):
371371
# Regenerate the PCI addresses so both pGPUs now support nvidia-12
372-
connection = self.computes[
373-
self.compute1.host].driver._host.get_connection()
374-
connection.pci_info = fakelibvirt.HostPCIDevicesInfo(
372+
pci_info = fakelibvirt.HostPCIDevicesInfo(
375373
num_pci=0, num_pfs=0, num_vfs=0, num_mdevcap=2,
376374
multiple_gpu_types=True)
377375
# Make a restart to update the Resource Providers
378-
self.compute1 = self.restart_compute_service(self.compute1)
376+
self.compute1 = self.restart_compute_service(
377+
self.compute1.host, pci_info=pci_info, keep_hypervisor_state=False)
379378
pgpu1_rp_uuid = self._get_provider_uuid_by_name(
380379
self.compute1.host + '_' + fakelibvirt.MDEVCAP_DEV1_PCI_ADDR)
381380
pgpu2_rp_uuid = self._get_provider_uuid_by_name(
@@ -451,7 +450,7 @@ def setUp(self):
451450
group='mdev_nvidia-12')
452451
self.flags(mdev_class='CUSTOM_NOTVGPU', group='mdev_mlx5_core')
453452

454-
self.compute1 = self.start_compute('host1')
453+
self.compute1 = self.start_compute_with_vgpu('host1')
455454
# Regenerate the PCI addresses so they can support both mlx5 and
456455
# nvidia-12 types
457456
connection = self.computes[
@@ -460,7 +459,7 @@ def setUp(self):
460459
num_pci=0, num_pfs=0, num_vfs=0, num_mdevcap=2,
461460
generic_types=True)
462461
# Make a restart to update the Resource Providers
463-
self.compute1 = self.restart_compute_service(self.compute1)
462+
self.compute1 = self.restart_compute_service('host1')
464463

465464
def test_create_servers_with_different_mdev_classes(self):
466465
physdev1_rp_uuid = self._get_provider_uuid_by_name(
@@ -498,7 +497,7 @@ def test_create_servers_with_different_mdev_classes(self):
498497

499498
def test_resize_servers_with_mlx5(self):
500499
# Add another compute for the sake of resizing
501-
self.compute2 = self.start_compute('host2')
500+
self.compute2 = self.start_compute_with_vgpu('host2')
502501
# Regenerate the PCI addresses so they can support both mlx5 and
503502
# nvidia-12 types
504503
connection = self.computes[
@@ -507,7 +506,7 @@ def test_resize_servers_with_mlx5(self):
507506
num_pci=0, num_pfs=0, num_vfs=0, num_mdevcap=2,
508507
generic_types=True)
509508
# Make a restart to update the Resource Providers
510-
self.compute2 = self.restart_compute_service(self.compute2)
509+
self.compute2 = self.restart_compute_service('host2')
511510

512511
# Use the new flavor for booting
513512
server = self._create_server(

0 commit comments

Comments
 (0)