@@ -114,7 +114,7 @@ def _get_connection(
114
114
def start_compute (
115
115
self , hostname = 'compute1' , host_info = None , pci_info = None ,
116
116
mdev_info = None , vdpa_info = None , libvirt_version = None ,
117
- qemu_version = None ,
117
+ qemu_version = None , cell_name = None , connection = None
118
118
):
119
119
"""Start a compute service.
120
120
@@ -124,16 +124,35 @@ def start_compute(
124
124
:param host_info: A fakelibvirt.HostInfo object for the host. Defaults
125
125
to a HostInfo with 2 NUMA nodes, 2 cores per node, 2 threads per
126
126
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.
127
130
:returns: The hostname of the created service, which can be used to
128
131
lookup the created service and UUID of the assocaited resource
129
132
provider.
130
133
"""
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
+ )
131
146
132
147
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
+
137
156
# If the compute is configured with PCI devices then we need to
138
157
# make sure that the stubs around sysfs has the MAC address
139
158
# information for the PCI PF devices
@@ -144,7 +163,8 @@ def _start_compute(hostname, host_info):
144
163
# actually start the service.
145
164
orig_con = self .mock_conn .return_value
146
165
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 )
148
168
# Once that's done, we need to tweak the compute "service" to
149
169
# make sure it returns unique objects.
150
170
compute .driver ._host .get_connection = lambda : fake_connection
@@ -165,6 +185,74 @@ def _start_compute(hostname, host_info):
165
185
166
186
return hostname
167
187
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
+
168
256
169
257
class LibvirtMigrationMixin (object ):
170
258
"""A simple mixin to facilliate successful libvirt live migrations
0 commit comments