Skip to content

Commit f98858a

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. Change-Id: Ic717dc42ac6b6cace59d344acaf12f9d1ee35564 (cherry picked from commit 57c253a)
1 parent 69667a8 commit f98858a

File tree

7 files changed

+127
-54
lines changed

7 files changed

+127
-54
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_device_bus_migration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def _assert_stashed_image_properties(self, server_id, properties):
5151

5252
def _assert_stashed_image_properties_persist(self, server, properties):
5353
# Assert the stashed properties persist across a host reboot
54-
self.restart_compute_service(self.compute)
54+
self.restart_compute_service(self.compute_hostname)
5555
self._assert_stashed_image_properties(server['id'], properties)
5656

5757
# Assert the stashed properties persist across a guest reboot
@@ -173,7 +173,7 @@ def test_default_image_property_persists_across_host_flag_changes(self):
173173
self.flags(pointer_model='ps2mouse')
174174
# Restart compute to pick up ps2 setting, which means the guest will
175175
# not get a prescribed pointer device
176-
self.restart_compute_service(self.compute)
176+
self.restart_compute_service(self.compute_hostname)
177177

178178
# Create a server with default image properties
179179
default_image_properties1 = {
@@ -187,7 +187,7 @@ def test_default_image_property_persists_across_host_flag_changes(self):
187187
# Assert the defaults persist across a host flag change
188188
self.flags(pointer_model='usbtablet')
189189
# Restart compute to pick up usb setting
190-
self.restart_compute_service(self.compute)
190+
self.restart_compute_service(self.compute_hostname)
191191
self._assert_stashed_image_properties(
192192
server1['id'], default_image_properties1)
193193

@@ -216,7 +216,7 @@ def test_default_image_property_persists_across_host_flag_changes(self):
216216
# https://bugs.launchpad.net/nova/+bug/1866106
217217
self.flags(pointer_model=None)
218218
# Restart compute to pick up None setting
219-
self.restart_compute_service(self.compute)
219+
self.restart_compute_service(self.compute_hostname)
220220
self._assert_stashed_image_properties(
221221
server1['id'], default_image_properties1)
222222
self._assert_stashed_image_properties(

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
@@ -914,11 +914,8 @@ def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
914914
# Disable SRIOV capabilties in PF and delete the VFs
915915
self._disable_sriov_in_pf(pci_info_no_sriov)
916916

917-
fake_connection = self._get_connection(pci_info=pci_info_no_sriov,
918-
hostname='test_compute0')
919-
self.mock_conn.return_value = fake_connection
920-
921-
self.compute = self.start_service('compute', host='test_compute0')
917+
self.start_compute('test_compute0', pci_info=pci_info_no_sriov)
918+
self.compute = self.computes['test_compute0']
922919

923920
ctxt = context.get_admin_context()
924921
pci_devices = objects.PciDeviceList.get_by_compute_node(
@@ -930,13 +927,9 @@ def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
930927
self.assertEqual(1, len(pci_devices))
931928
self.assertEqual('type-PCI', pci_devices[0].dev_type)
932929

933-
# Update connection with original pci info with sriov PFs
934-
fake_connection = self._get_connection(pci_info=pci_info,
935-
hostname='test_compute0')
936-
self.mock_conn.return_value = fake_connection
937-
938-
# Restart the compute service
939-
self.restart_compute_service(self.compute)
930+
# Restart the compute service with sriov PFs
931+
self.restart_compute_service(
932+
self.compute.host, pci_info=pci_info, keep_hypervisor_state=False)
940933

941934
# Verify if PCI devices are of type type-PF or type-VF
942935
pci_devices = objects.PciDeviceList.get_by_compute_node(
@@ -1021,10 +1014,9 @@ def _test_detach_attach(self, first_port_id, second_port_id):
10211014
host_info = fakelibvirt.HostInfo(cpu_nodes=2, cpu_sockets=1,
10221015
cpu_cores=2, cpu_threads=2)
10231016
pci_info = fakelibvirt.HostPCIDevicesInfo(num_pfs=1, num_vfs=1)
1024-
fake_connection = self._get_connection(host_info, pci_info)
1025-
self.mock_conn.return_value = fake_connection
1026-
1027-
self.compute = self.start_service('compute', host='test_compute0')
1017+
self.start_compute(
1018+
'test_compute0', host_info=host_info, pci_info=pci_info)
1019+
self.compute = self.computes['test_compute0']
10281020

10291021
# Create server with a port
10301022
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)