Merge "Add/Remove the volume BDMs during resize"

This commit is contained in:
Jenkins 2015-11-02 19:14:02 +00:00 committed by Gerrit Code Review
commit 69215ddc54
2 changed files with 132 additions and 28 deletions

View File

@ -890,21 +890,24 @@ class TestPowerVMDriver(test.TestCase):
resp.entry = pvm_lpar.LPAR._bld(None).entry
self.apt.read.return_value = resp
# BDMs
mock_bdms = self._fake_bdms()
# Catch root disk resize smaller.
small_root = objects.Flavor(vcpus=1, memory_mb=2048, root_gb=9)
self.assertRaises(
exc.InstanceFaultRollback, self.drv.migrate_disk_and_power_off,
'context', inst, 'dest', small_root, 'network_info')
'context', inst, 'dest', small_root, 'network_info', mock_bdms)
new_flav = objects.Flavor(vcpus=1, memory_mb=2048, root_gb=10)
# We don't support resize to different host.
self.assertRaises(
NotImplementedError, self.drv.migrate_disk_and_power_off,
'context', inst, 'bogus host', new_flav, 'network_info')
'context', inst, 'bogus host', new_flav, 'network_info', mock_bdms)
self.drv.migrate_disk_and_power_off(
'context', inst, host, new_flav, 'network_info')
'context', inst, host, new_flav, 'network_info', mock_bdms)
mock_pwr_off.assert_called_with(
self.drv.adapter, inst, self.drv.host_uuid, entry=mock.ANY)
mock_update.assert_called_with(
@ -914,7 +917,7 @@ class TestPowerVMDriver(test.TestCase):
# Boot disk resize
boot_flav = objects.Flavor(vcpus=1, memory_mb=2048, root_gb=12)
self.drv.migrate_disk_and_power_off(
'context', inst, host, boot_flav, 'network_info')
'context', inst, host, boot_flav, 'network_info', mock_bdms)
self.drv.disk_dvr.extend_disk.assert_called_with(
'context', inst, dict(type='boot'), 12)

View File

@ -249,19 +249,8 @@ class PowerVMDriver(driver.ComputeDriver):
# Determine if there are volumes to connect. If so, add a connection
# for each type.
if bdms is not None:
for bdm in bdms:
conn_info = bdm.get('connection_info')
vol_drv = self._get_inst_vol_adpt(
context, instance, conn_info=conn_info, stg_ftsk=stg_ftsk)
# First connect the volume. This will update the
# connection_info.
flow_spawn.add(tf_stg.ConnectVolume(vol_drv))
# Save the BDM so that the updated connection info is
# persisted.
flow_spawn.add(tf_stg.SaveBDM(bdm, instance))
self._add_volume_connection_tasks(
context, instance, bdms, flow_spawn, stg_ftsk)
# If the config drive is needed, add those steps. Should be done
# after all the other I/O.
@ -288,6 +277,52 @@ class PowerVMDriver(driver.ComputeDriver):
# Run the flow.
tf_eng.run(flow_spawn)
def _add_volume_connection_tasks(self, context, instance, bdms,
flow, stg_ftsk):
"""Determine if there are volumes to connect to this instance.
If there are volumes to connect to this instance add a task to the
flow for each volume.
:param context: security context.
:param instance: Instance object as returned by DB layer.
:param bdms: block device mappings.
:param flow: the flow to add the tasks to.
:param stg_ftsk: the storage task flow.
"""
for bdm in bdms or []:
conn_info = bdm.get('connection_info')
vol_drv = self._get_inst_vol_adpt(
context, instance, conn_info=conn_info, stg_ftsk=stg_ftsk)
# First connect the volume. This will update the
# connection_info.
flow.add(tf_stg.ConnectVolume(vol_drv))
# Save the BDM so that the updated connection info is
# persisted.
flow.add(tf_stg.SaveBDM(bdm, instance))
def _add_volume_disconnection_tasks(self, context, instance, bdms,
flow, stg_ftsk):
"""Determine if there are volumes to disconnect from this instance.
If there are volumes to disconnect from this instance add a task to the
flow for each volume.
:param context: security context.
:param instance: Instance object as returned by DB layer.
:param bdms: block device mappings.
:param flow: the flow to add the tasks to.
:param stg_ftsk: the storage task flow.
"""
for bdm in bdms or []:
conn_info = bdm.get('connection_info')
vol_drv = self._get_inst_vol_adpt(
context, instance, conn_info=conn_info,
stg_ftsk=stg_ftsk)
flow.add(tf_stg.DisconnectVolume(vol_drv))
def _is_booted_from_volume(self, block_device_info):
"""Determine whether the root device is listed in block_device_info.
@ -347,13 +382,8 @@ class PowerVMDriver(driver.ComputeDriver):
# Determine if there are volumes to disconnect. If so, remove each
# volume (within the transaction manager)
if bdms is not None:
for bdm in bdms:
conn_info = bdm.get('connection_info')
vol_drv = self._get_inst_vol_adpt(
context, instance, conn_info=conn_info,
stg_ftsk=stg_ftsk)
flow.add(tf_stg.DisconnectVolume(vol_drv))
self._add_volume_disconnection_tasks(context, instance, bdms, flow,
stg_ftsk)
# Only attach the disk adapters if this is not a boot from volume.
destroy_disk_task = None
@ -788,6 +818,43 @@ class PowerVMDriver(driver.ComputeDriver):
connector["wwpns"] = wwpn_list
return connector
def _remove_volume_connections(self, context, instance, block_device_info):
"""Removes the volume connections for the instance.
During resize disconnect if there are any volumes connected
to an instance.
:param context: security context
:param instance: Instance object
:param block_device_info: Information about block devices that should
be detached from the instance.
"""
# Extract the block devices.
bdms = self._extract_bdm(block_device_info)
# Nothing needed if there isn't a bdms.
if not bdms:
return
# Define the flow
flow = tf_lf.Flow("resize_vm")
# Create the transaction manager (FeedTask) for Storage I/O.
xag = self._get_inst_xag(instance, bdms)
stg_ftsk = vios.build_tx_feed_task(self.adapter, self.host_uuid,
xag=xag)
# Determine if there are volumes to disconnect. If so, remove each
# volume (within the transaction manager)
self._add_volume_disconnection_tasks(context, instance, bdms, flow,
stg_ftsk)
if len(flow):
# Add the transaction manager flow to the end of the 'storage
# disconnection' tasks. This will run all the connections in
# parallel
flow.add(stg_ftsk)
# Build the engine & run
tf_eng.run(flow)
def migrate_disk_and_power_off(self, context, instance, dest,
flavor, network_info,
block_device_info=None,
@ -818,6 +885,13 @@ class PowerVMDriver(driver.ComputeDriver):
# Do any VM resource changes
self._resize_vm(context, instance, flav_obj, retry_interval)
# If everything has gone well up to this point, the compute
# manager is going to terminate the volume connections for the
# instance, so we need to remove our mappings.
# Remove the volume connections for the BDMs
self._remove_volume_connections(context, instance,
block_device_info)
else:
self._log_operation('migration', instance)
raise NotImplementedError()
@ -865,16 +939,43 @@ class PowerVMDriver(driver.ComputeDriver):
:param image_meta: image object returned by nova.image.glance that
defines the image from which this instance
was created
:param resize_instance: True if the instance is being resized,
:param resize_instance: True if the instance disks are being resized,
False otherwise
:param block_device_info: instance volume block device info
:param power_on: True if the instance should be powered on, False
otherwise
"""
# TODO(IBM): Finish this up
# Extract the block devices.
bdms = self._extract_bdm(block_device_info)
# Nothing needed if there isn't a bdms or a requirement to power-on.
if not bdms and not power_on:
return
# Define the flow
flow = tf_lf.Flow("finish_migration")
if bdms:
# Create the transaction manager (FeedTask) for Storage I/O.
xag = self._get_inst_xag(instance, bdms)
stg_ftsk = vios.build_tx_feed_task(self.adapter, self.host_uuid,
xag=xag)
# Determine if there are volumes to connect. If so, add a
# connection for each type.
self._add_volume_connection_tasks(context, instance, bdms,
flow, stg_ftsk)
if len(flow):
# Add the transaction manager flow to the end of the 'storage
# connection' tasks to run all the connections in parallel
flow.add(stg_ftsk)
if power_on:
vm.power_on(self.adapter, instance, self.host_uuid)
# Get the lpar wrapper (required by power-on), then power-on
flow.add(tf_vm.Get(self.adapter, self.host_uuid, instance))
flow.add(tf_vm.PowerOn(self.adapter, self.host_uuid, instance))
if len(flow):
tf_eng.run(flow)
def confirm_migration(self, migration, instance, network_info):
"""Confirms a resize, destroying the source VM.
@ -910,7 +1011,7 @@ class PowerVMDriver(driver.ComputeDriver):
instance.instance_type_id))
# TODO(IBM) Get the entry once for both power_off and update
vm.power_off(self.adapter, instance, self.host_uuid)
vm.update(self.adapter, self.host_uuid, instance, flav_obj)
vm.update(self.adapter, self.host_wrapper, instance, flav_obj)
if power_on:
vm.power_on(self.adapter, instance, self.host_uuid)