@locked_detach_operation
def detach_volume(self, context, volume_id, attachment_id=None):
    'Updates db to show volume is detached.'
    volume = self.db.volume_get(context, volume_id)
    attachment = None
    if attachment_id:
        try:
            attachment = self.db.volume_attachment_get(context, attachment_id)
        except exception.VolumeAttachmentNotFound:
            LOG.info(_LI('Volume detach called, but volume not attached.'), resource=volume)
            self.db.volume_detached(context, volume_id, attachment_id)
            return
    else:
        attachments = self.db.volume_attachment_get_all_by_volume_id(context, volume_id)
        if (len(attachments) > 1):
            msg = _('Detach volume failed: More than one attachment, but no attachment_id provided.')
            LOG.error(msg, resource=volume)
            raise exception.InvalidVolume(reason=msg)
        elif (len(attachments) == 1):
            attachment = attachments[0]
        else:
            LOG.info(_LI('Volume detach called, but volume not attached.'), resource=volume)
            self.db.volume_update(context, volume_id, {'status': 'available', 'attach_status': 'detached'})
            return
    self._notify_about_volume_usage(context, volume, 'detach.start')
    try:
        utils.require_driver_initialized(self.driver)
        LOG.debug('Detaching volume %(volume_id)s from instance %(instance)s.', {'volume_id': volume_id, 'instance': attachment.get('instance_uuid')}, resource=volume)
        self.driver.detach_volume(context, volume, attachment)
    except Exception:
        with excutils.save_and_reraise_exception():
            self.db.volume_attachment_update(context, attachment.get('id'), {'attach_status': 'error_detaching'})
    self.db.volume_detached(context.elevated(), volume_id, attachment.get('id'))
    self.db.volume_admin_metadata_delete(context.elevated(), volume_id, 'attached_mode')
    volume = self.db.volume_get(context, volume_id)
    try:
        utils.require_driver_initialized(self.driver)
        self.driver.remove_export(context.elevated(), volume)
    except exception.DriverNotInitialized:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE('Detach volume failed, due to uninitialized driver.'), resource=volume)
    except Exception as ex:
        LOG.exception(_LE('Detach volume failed, due to remove-export failure.'), resource=volume)
        raise exception.RemoveExportException(volume=volume_id, reason=six.text_type(ex))
    self._notify_about_volume_usage(context, volume, 'detach.end')
    LOG.info(_LI('Detach volume completed successfully.'), resource=volume)
Updates db to show volume is detached.
@locked_detach_operation
def detach_volume(self, context, volume_id, attachment_id=None):
    
    volume = self.db.volume_get(context, volume_id)
    attachment = None
    if attachment_id:
        try:
            attachment = self.db.volume_attachment_get(context, attachment_id)
        except exception.VolumeAttachmentNotFound:
            LOG.info(_LI('Volume detach called, but volume not attached.'), resource=volume)
            self.db.volume_detached(context, volume_id, attachment_id)
            return
    else:
        attachments = self.db.volume_attachment_get_all_by_volume_id(context, volume_id)
        if (len(attachments) > 1):
            msg = _('Detach volume failed: More than one attachment, but no attachment_id provided.')
            LOG.error(msg, resource=volume)
            raise exception.InvalidVolume(reason=msg)
        elif (len(attachments) == 1):
            attachment = attachments[0]
        else:
            LOG.info(_LI('Volume detach called, but volume not attached.'), resource=volume)
            self.db.volume_update(context, volume_id, {'status': 'available', 'attach_status': 'detached'})
            return
    self._notify_about_volume_usage(context, volume, 'detach.start')
    try:
        utils.require_driver_initialized(self.driver)
        LOG.debug('Detaching volume %(volume_id)s from instance %(instance)s.', {'volume_id': volume_id, 'instance': attachment.get('instance_uuid')}, resource=volume)
        self.driver.detach_volume(context, volume, attachment)
    except Exception:
        with excutils.save_and_reraise_exception():
            self.db.volume_attachment_update(context, attachment.get('id'), {'attach_status': 'error_detaching'})
    self.db.volume_detached(context.elevated(), volume_id, attachment.get('id'))
    self.db.volume_admin_metadata_delete(context.elevated(), volume_id, 'attached_mode')
    volume = self.db.volume_get(context, volume_id)
    try:
        utils.require_driver_initialized(self.driver)
        self.driver.remove_export(context.elevated(), volume)
    except exception.DriverNotInitialized:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE('Detach volume failed, due to uninitialized driver.'), resource=volume)
    except Exception as ex:
        LOG.exception(_LE('Detach volume failed, due to remove-export failure.'), resource=volume)
        raise exception.RemoveExportException(volume=volume_id, reason=six.text_type(ex))
    self._notify_about_volume_usage(context, volume, 'detach.end')
    LOG.info(_LI('Detach volume completed successfully.'), resource=volume)