Skip to content

Commit d0d474f

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add compute restart capability for libvirt func tests" into stable/xena
2 parents 5e8cad2 + afc55c5 commit d0d474f

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)