Add power_on kwarg to ComputeDriver.spawn() method

For a cross-cell resize, the equivalent of the "finish_resize"
method on the destination compute is going to call the
driver spawn() method rather than the finish_migration()
method and needs to pass through the power_on value, similar
to finish_migration, so that when resizing a stopped server
it remains stopped once it is resized.

The finish_migration method in the driver behaves very similar
to spawn so the semantics are the same.

This change updates the spawn method signature for all in-tree
compute drivers but only implements the logic for the libvirt
driver as that is the only driver (currently) which supports
cross-cell resize (note the can_connect_volume method is also
necessary for cross-cell resize implementation in the driver).

Part of blueprint cross-cell-resize

Change-Id: I6929c588dd2e0e805f2e30b2e30d29967469d756
This commit is contained in:
Matt Riedemann 2019-03-11 12:19:13 -04:00
parent f7e7a07bdd
commit a958dc5fcc
10 changed files with 48 additions and 25 deletions

View File

@ -12857,7 +12857,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_stat.assert_called_once_with(path)
mock_get_size.assert_called_once_with(path)
def test_spawn_with_network_info(self):
def test_spawn_with_network_info(self, power_on=True):
def fake_getLibVersion():
return fakelibvirt.FAKE_LIBVIRT_VERSION
@ -12918,19 +12918,29 @@ class LibvirtConnTestCase(test.NoDBTestCase,
):
self.flags(instances_path=tmpdir)
hw_running = hardware.InstanceInfo(state=power_state.RUNNING)
mock_get_info.return_value = hw_running
if power_on:
hw_running = hardware.InstanceInfo(state=power_state.RUNNING)
mock_get_info.return_value = hw_running
else:
# Avoid a test timeout since _wait_for_boot is threaded.
mock_get_info.side_effect = Exception('do not call get_info')
mock_build_device_metadata.return_value = None
del mock_orig_libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES
drvr.spawn(self.context, instance, image_meta, [], 'herp', {},
network_info=network_info)
network_info=network_info, power_on=power_on)
mock_get_info.assert_called_once_with(instance)
if power_on:
mock_get_info.assert_called_once_with(instance)
else:
mock_get_info.assert_not_called()
mock_build_device_metadata.assert_called_once_with(self.context,
instance)
def test_spawn_power_on_false(self):
self.test_spawn_with_network_info(power_on=False)
# Methods called directly by spawn()
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_guest_xml')
@mock.patch.object(libvirt_driver.LibvirtDriver,

View File

@ -342,11 +342,12 @@ class ComputeDriver(object):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
"""Create a new instance/VM/domain on the virtualization platform.
Once this successfully completes, the instance should be
running (power_state.RUNNING).
running (power_state.RUNNING) if ``power_on`` is True, else the
instance should be stopped (power_state.SHUTDOWN).
If this fails, any partial instance should be completely
cleaned up, and the virtualization platform should be in the state
@ -366,6 +367,8 @@ class ComputeDriver(object):
:param network_info: instance network information
:param block_device_info: Information about block devices to be
attached to the instance.
:param power_on: True if the instance should be powered on, False
otherwise
"""
raise NotImplementedError()

View File

@ -179,7 +179,7 @@ class FakeDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
if network_info:
for vif in network_info:
@ -191,7 +191,7 @@ class FakeDriver(driver.ComputeDriver):
self._interfaces[vif['id']] = vif
uuid = instance.uuid
state = power_state.RUNNING
state = power_state.RUNNING if power_on else power_state.SHUTDOWN
flavor = instance.flavor
self.resources.claim(
vcpus=flavor.vcpus,
@ -593,7 +593,7 @@ class FakeDriver(driver.ComputeDriver):
# claim resources and track the instance on this "hypervisor".
self.spawn(context, instance, image_meta, injected_files,
admin_password, allocations,
block_device_info=block_device_info)
block_device_info=block_device_info, power_on=power_on)
def confirm_migration(self, context, migration, instance, network_info):
# Confirm migration cleans up the guest from the source host so just
@ -764,7 +764,7 @@ class FakeRescheduleDriver(FakeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
if not self.rescheduled.get(instance.uuid, False):
# We only reschedule on the first time something hits spawn().
self.rescheduled[instance.uuid] = True
@ -772,7 +772,8 @@ class FakeRescheduleDriver(FakeDriver):
reason='FakeRescheduleDriver')
super(FakeRescheduleDriver, self).spawn(
context, instance, image_meta, injected_files,
admin_password, allocations, network_info, block_device_info)
admin_password, allocations, network_info, block_device_info,
power_on)
class FakeRescheduleDriverWithNestedCustomResources(
@ -786,7 +787,7 @@ class FakeBuildAbortDriver(FakeDriver):
"""
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
raise exception.BuildAbortException(
instance_uuid=instance.uuid, reason='FakeBuildAbortDriver')
@ -802,14 +803,15 @@ class FakeUnshelveSpawnFailDriver(FakeDriver):
"""
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
if instance.vm_state == vm_states.SHELVED_OFFLOADED:
raise exception.VirtualInterfaceCreateException(
'FakeUnshelveSpawnFailDriver')
# Otherwise spawn normally during the initial build.
super(FakeUnshelveSpawnFailDriver, self).spawn(
context, instance, image_meta, injected_files,
admin_password, allocations, network_info, block_device_info)
admin_password, allocations, network_info, block_device_info,
power_on)
class FakeUnshelveSpawnFailDriverWithNestedCustomResources(

View File

@ -159,7 +159,7 @@ class HyperVDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
self._vmops.spawn(context, instance, image_meta, injected_files,
admin_password, network_info, block_device_info)

View File

@ -1112,7 +1112,7 @@ class IronicDriver(virt_driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
"""Deploy an instance.
:param context: The security context.
@ -1129,6 +1129,8 @@ class IronicDriver(virt_driver.ComputeDriver):
:param network_info: Instance network information.
:param block_device_info: Instance block device
information.
:param power_on: True if the instance should be powered on, False
otherwise
"""
LOG.debug('Spawn called for instance', instance=instance)

View File

@ -3199,7 +3199,7 @@ class LibvirtDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance,
image_meta,
@ -3228,7 +3228,8 @@ class LibvirtDriver(driver.ComputeDriver):
context, xml, instance, network_info,
block_device_info=block_device_info,
post_xml_callback=gen_confdrive,
destroy_disks_on_failure=True)
destroy_disks_on_failure=True,
power_on=power_on)
LOG.debug("Guest created on hypervisor", instance=instance)
def _wait_for_boot():
@ -3239,8 +3240,11 @@ class LibvirtDriver(driver.ComputeDriver):
LOG.info("Instance spawned successfully.", instance=instance)
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot)
timer.start(interval=0.5).wait()
if power_on:
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot)
timer.start(interval=0.5).wait()
else:
LOG.info("Instance spawned successfully.", instance=instance)
def _get_console_output_file(self, instance, console_log):
bytes_to_read = MAX_CONSOLE_BYTES

View File

@ -240,7 +240,7 @@ class PowerVMDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
"""Create a new instance/VM/domain on the virtualization platform.
Once this successfully completes, the instance should be
@ -264,6 +264,8 @@ class PowerVMDriver(driver.ComputeDriver):
:param network_info: instance network information
:param block_device_info: Information about block devices to be
attached to the instance.
:param power_on: True if the instance should be powered on, False
otherwise
"""
self._log_operation('spawn', instance)
# Define the flow

View File

@ -537,7 +537,7 @@ class VMwareVCDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
"""Create VM instance."""
self._vmops.spawn(context, instance, image_meta, injected_files,
admin_password, network_info, block_device_info)

View File

@ -212,7 +212,7 @@ class XenAPIDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
"""Create VM instance."""
vgpu_info = self._get_vgpu_info(allocations)
self._vmops.spawn(context, instance, image_meta, injected_files,

View File

@ -141,7 +141,7 @@ class ZVMDriver(driver.ComputeDriver):
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
block_device_info=None, power_on=True):
LOG.info("Spawning new instance %s on zVM hypervisor",
instance.name, instance=instance)