Refactor driver BDM attach() to cover all uses
Add separate flags to allow the execution to skip the volume_api.check_attach step, and to be able to call the driver.attach_volume if needed. This will make the method modular enough to be used in all cases where we actually "attach" volumes to instances. Check attach should always be done in the API, followed immediately by a reservation, to minimize the chance of a race. However currently we do the check_attach step on the compute side during boot, so it needs to stay. Other operations like attach_volume will have it reserved causing this check to fail on the compute side, so we lay down the groundwork to be able to skip it when calling attach(). Likewise, when booting, we don't need to call the virt driver attach_volume method, as all the devices will be taken care of by the boot code path. Part of blueprint: use-new-bdm-format-in-attach Change-Id: Iff3890e39a8c75b1693df0918084ecf4492c4e91
This commit is contained in:
@@ -17,9 +17,11 @@ import operator
|
||||
|
||||
from nova import block_device
|
||||
from nova.objects import block_device as block_device_obj
|
||||
from nova.openstack.common import excutils
|
||||
from nova.openstack.common.gettextutils import _
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.volume import encryptors
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@@ -209,14 +211,12 @@ class DriverVolumeBlockDevice(DriverBlockDevice):
|
||||
self['connection_info'] = None
|
||||
|
||||
@update_db
|
||||
def attach(self, context, instance, volume_api, virt_driver):
|
||||
def attach(self, context, instance, volume_api, virt_driver,
|
||||
do_check_attach=True, do_driver_attach=False):
|
||||
volume = volume_api.get(context, self.volume_id)
|
||||
volume_api.check_attach(context, volume, instance=instance)
|
||||
if do_check_attach:
|
||||
volume_api.check_attach(context, volume, instance=instance)
|
||||
|
||||
# Attach a volume to an instance at boot time. So actual attach
|
||||
# is done by instance creation.
|
||||
instance_id = instance['id']
|
||||
instance_uuid = instance['uuid']
|
||||
volume_id = volume['id']
|
||||
context = context.elevated()
|
||||
|
||||
@@ -224,12 +224,31 @@ class DriverVolumeBlockDevice(DriverBlockDevice):
|
||||
connection_info = volume_api.initialize_connection(context,
|
||||
volume_id,
|
||||
connector)
|
||||
volume_api.attach(context, volume_id,
|
||||
instance_uuid, self['mount_device'])
|
||||
|
||||
if 'serial' not in connection_info:
|
||||
connection_info['serial'] = self.volume_id
|
||||
|
||||
# If do_driver_attach is False, we will attach a volume to an instance
|
||||
# at boot time. So actual attach is done by instance creation code.
|
||||
if do_driver_attach:
|
||||
encryption = encryptors.get_encryption_metadata(
|
||||
context, volume_api, volume_id, connection_info)
|
||||
|
||||
try:
|
||||
virt_driver.attach_volume(
|
||||
context, connection_info, instance,
|
||||
self['mount_device'], encryption=encryption)
|
||||
except Exception: # pylint: disable=W0702
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_("Driver failed to attach volume "
|
||||
"%(volume_id)s at %(mountpoint)s"),
|
||||
{'volume_id': volume_id,
|
||||
'mountpoint': self['mount_device']},
|
||||
context=context, instance=instance)
|
||||
volume_api.terminate_connection(context, volume_id,
|
||||
connector)
|
||||
self['connection_info'] = connection_info
|
||||
volume_api.attach(context, volume_id,
|
||||
instance['uuid'], self['mount_device'])
|
||||
|
||||
@update_db
|
||||
def refresh_connection_info(self, context, instance,
|
||||
|
||||
Reference in New Issue
Block a user