def create(self, context, volume_id, display_name): """Creates an entry in the transfers table.""" volume_api.check_policy(context, 'create_transfer') LOG.info(_LI("Generating transfer record for volume %s"), volume_id) volume_ref = self.db.volume_get(context, volume_id) if volume_ref['status'] != "available": raise exception.InvalidVolume(reason=_("status must be available")) volume_utils.notify_about_volume_usage(context, volume_ref, "transfer.create.start") # The salt is just a short random string. salt = self._get_random_string(CONF.volume_transfer_salt_length) auth_key = self._get_random_string(CONF.volume_transfer_key_length) crypt_hash = self._get_crypt_hash(salt, auth_key) # TODO(ollie): Transfer expiry needs to be implemented. transfer_rec = {'volume_id': volume_id, 'display_name': display_name, 'salt': salt, 'crypt_hash': crypt_hash, 'expires_at': None} try: transfer = self.db.transfer_create(context, transfer_rec) except Exception: LOG.error(_LE("Failed to create transfer record " "for %s"), volume_id) raise volume_utils.notify_about_volume_usage(context, volume_ref, "transfer.create.end") return {'id': transfer['id'], 'volume_id': transfer['volume_id'], 'display_name': transfer['display_name'], 'auth_key': auth_key, 'created_at': transfer['created_at']}
def get_all(self, context, filters={}): volume_api.check_policy(context, "get_all_transfers") if context.is_admin and "all_tenants" in filters: transfers = self.db.transfer_get_all(context) else: transfers = self.db.transfer_get_all_by_project(context, context.project_id) return transfers
def create(self, context, volume_id, display_name): """Creates an entry in the transfers table.""" volume_api.check_policy(context, "create_transfer") LOG.info("Generating transfer record for volume %s" % volume_id) volume_ref = self.db.volume_get(context, volume_id) if volume_ref["status"] != "available": raise exception.InvalidVolume(reason=_("status must be available")) # The salt is just a short random string. salt = self._get_random_string(CONF.volume_transfer_salt_length) auth_key = self._get_random_string(CONF.volume_transfer_key_length) crypt_hash = self._get_crypt_hash(salt, auth_key) # TODO(ollie): Transfer expiry needs to be implemented. transfer_rec = { "volume_id": volume_id, "display_name": display_name, "salt": salt, "crypt_hash": crypt_hash, "expires_at": None, } try: transfer = self.db.transfer_create(context, transfer_rec) except Exception: LOG.error(_LE("Failed to create transfer record " "for %s") % volume_id) raise return { "id": transfer["id"], "volume_id": transfer["volume_id"], "display_name": transfer["display_name"], "auth_key": auth_key, "created_at": transfer["created_at"], }
def get_all(self, context, filters=None): filters = filters or {} volume_api.check_policy(context, 'get_all_transfers') if context.is_admin and 'all_tenants' in filters: transfers = self.db.transfer_get_all(context) else: transfers = self.db.transfer_get_all_by_project(context, context.project_id) return transfers
def delete(self, context, transfer_id): """Make the RPC call to delete a volume transfer.""" volume_api.check_policy(context, 'delete_transfer') transfer = self.db.transfer_get(context, transfer_id) volume_ref = self.db.volume_get(context, transfer.volume_id) if volume_ref['status'] != 'awaiting-transfer': LOG.error(_LE("Volume in unexpected state")) self.db.transfer_destroy(context, transfer_id)
def delete(self, context, transfer_id): """Make the RPC call to delete a volume transfer.""" volume_api.check_policy(context, "delete_transfer") transfer = self.db.transfer_get(context, transfer_id) volume_ref = self.db.volume_get(context, transfer.volume_id) if volume_ref["status"] != "awaiting-transfer": msg = _("Volume in unexpected state") LOG.error(msg) self.db.transfer_destroy(context, transfer_id)
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, "accept_transfer") transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer["salt"], auth_key) if crypt_hash != transfer["crypt_hash"]: msg = _("Attempt to transfer %s with invalid auth key.") % transfer_id LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer["volume_id"] vol_ref = self.db.volume_get(context.elevated(), volume_id) if vol_ref["consistencygroup_id"]: msg = _("Volume %s must not be part of a consistency " "group.") % vol_ref["id"] LOG.error(msg) raise exception.InvalidVolume(reason=msg) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.start") try: reserve_opts = {"volumes": 1, "gigabytes": vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: quota_utils.process_reserve_over_quota(context, e, resource="volumes", size=vol_ref.size) try: donor_id = vol_ref["project_id"] reserve_opts = {"volumes": -1, "gigabytes": -vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, **reserve_opts) except Exception: donor_reservations = None LOG.exception(_LE("Failed to update quota donating volume" " transfer id %s"), transfer_id) try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_LI("Volume %s has been transferred."), volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.end") return {"id": transfer_id, "display_name": transfer["display_name"], "volume_id": vol_ref["id"]}
def delete(self, context, transfer_id): """Make the RPC call to delete a volume transfer.""" volume_api.check_policy(context, "delete_transfer") transfer = self.db.transfer_get(context, transfer_id) volume_ref = self.db.volume_get(context, transfer.volume_id) volume_utils.notify_about_volume_usage(context, volume_ref, "transfer.delete.start") if volume_ref["status"] != "awaiting-transfer": LOG.error(_LE("Volume in unexpected state")) self.db.transfer_destroy(context, transfer_id) volume_utils.notify_about_volume_usage(context, volume_ref, "transfer.delete.end")
def create(self, context, volume_id, display_name): """Creates an entry in the transfers table.""" volume_api.check_policy(context, 'create_transfer') LOG.info("Generating transfer record for volume %s" % volume_id) volume_ref = self.db.volume_get(context, volume_id) if volume_ref['status'] != "available": raise exception.InvalidVolume(reason=_("status must be available")) # The salt is just a short random string. salt = self._get_random_string(CONF.volume_transfer_salt_length) auth_key = self._get_random_string(CONF.volume_transfer_key_length) crypt_hash = self._get_crypt_hash(salt, auth_key) # TODO(ollie): Transfer expiry needs to be implemented. transfer_rec = { 'volume_id': volume_id, 'display_name': display_name, 'salt': salt, 'crypt_hash': crypt_hash, 'expires_at': None } try: transfer = self.db.transfer_create(context, transfer_rec) except Exception: LOG.error( _LE("Failed to create transfer record " "for %s") % volume_id) raise return { 'id': transfer['id'], 'volume_id': transfer['volume_id'], 'display_name': transfer['display_name'], 'auth_key': auth_key, 'created_at': transfer['created_at'] }
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, 'accept_transfer') transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer['salt'], auth_key) if crypt_hash != transfer['crypt_hash']: msg = (_("Attempt to transfer %s with invalid auth key.") % transfer_id) LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer['volume_id'] vol_ref = self.db.volume_get(context.elevated(), volume_id) try: reservations = QUOTAS.reserve(context, volumes=1, gigabytes=vol_ref['size']) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: msg = _("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG volume (%(d_consumed)dG of %(d_quota)dG " "already consumed)") LOG.warn( msg % { 's_pid': context.project_id, 's_size': vol_ref['size'], 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.VolumeSizeExceedsAvailableQuota() elif 'volumes' in overs: msg = _("Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)") LOG.warn( msg % { 's_pid': context.project_id, 'd_consumed': _consumed('volumes') }) raise exception.VolumeLimitExceeded(allowed=quotas['volumes']) try: donor_id = vol_ref['project_id'] donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, volumes=-1, gigabytes=-vol_ref['size']) except Exception: donor_reservations = None LOG.exception( _("Failed to update quota donating volume" "transfer id %s") % transfer_id) try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_("Volume %s has been transferred.") % volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) return { 'id': transfer_id, 'display_name': transfer['display_name'], 'volume_id': vol_ref['id'] }
def get(self, context, transfer_id): volume_api.check_policy(context, 'get_transfer') rv = self.db.transfer_get(context, transfer_id) return dict(rv)
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, 'accept_transfer') transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer['salt'], auth_key) if crypt_hash != transfer['crypt_hash']: msg = (_("Attempt to transfer %s with invalid auth key.") % transfer_id) LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer['volume_id'] vol_ref = self.db.volume_get(context.elevated(), volume_id) if vol_ref['consistencygroup_id']: msg = _("Volume %s must not be part of a consistency " "group.") % vol_ref['id'] LOG.error(msg) raise exception.InvalidVolume(reason=msg) try: values = {'per_volume_gigabytes': vol_ref.size} QUOTAS.limit_check(context, project_id=context.project_id, **values) except exception.OverQuota as e: quotas = e.kwargs['quotas'] raise exception.VolumeSizeExceedsLimit( size=vol_ref.size, limit=quotas['per_volume_gigabytes']) try: reserve_opts = {'volumes': 1, 'gigabytes': vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: quota_utils.process_reserve_over_quota(context, e, resource='volumes', size=vol_ref.size) try: donor_id = vol_ref['project_id'] reserve_opts = {'volumes': -1, 'gigabytes': -vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, **reserve_opts) except Exception: donor_reservations = None LOG.exception(_LE("Failed to update quota donating volume" " transfer id %s"), transfer_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.start") try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_LI("Volume %s has been transferred."), volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.end") return {'id': transfer_id, 'display_name': transfer['display_name'], 'volume_id': vol_ref['id']}
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, 'accept_transfer') transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer['salt'], auth_key) if crypt_hash != transfer['crypt_hash']: msg = (_("Attempt to transfer %s with invalid auth key.") % transfer_id) LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer['volume_id'] vol_ref = objects.Volume.get_by_id(context.elevated(), volume_id) if vol_ref['consistencygroup_id']: msg = _("Volume %s must not be part of a consistency " "group.") % vol_ref['id'] LOG.error(msg) raise exception.InvalidVolume(reason=msg) try: values = {'per_volume_gigabytes': vol_ref.size} QUOTAS.limit_check(context, project_id=context.project_id, **values) except exception.OverQuota as e: quotas = e.kwargs['quotas'] raise exception.VolumeSizeExceedsLimit( size=vol_ref.size, limit=quotas['per_volume_gigabytes']) try: reserve_opts = {'volumes': 1, 'gigabytes': vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: quota_utils.process_reserve_over_quota(context, e, resource='volumes', size=vol_ref.size) try: donor_id = vol_ref['project_id'] reserve_opts = {'volumes': -1, 'gigabytes': -vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, **reserve_opts) except Exception: donor_reservations = None LOG.exception("Failed to update quota donating volume" " transfer id %s", transfer_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.start") try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info("Volume %s has been transferred.", volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.end") return {'id': transfer_id, 'display_name': transfer['display_name'], 'volume_id': vol_ref['id']}
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, 'accept_transfer') transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer['salt'], auth_key) if crypt_hash != transfer['crypt_hash']: msg = (_("Attempt to transfer %s with invalid auth key.") % transfer_id) LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer['volume_id'] vol_ref = self.db.volume_get(context.elevated(), volume_id) if vol_ref['consistencygroup_id']: msg = _("Volume %s must not be part of a consistency " "group.") % vol_ref['id'] LOG.error(msg) raise exception.InvalidVolume(reason=msg) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.start") try: reserve_opts = {'volumes': 1, 'gigabytes': vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) for over in overs: if 'gigabytes' in over: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG volume (%(d_consumed)dG of " "%(d_quota)dG already consumed)") LOG.warning( msg, { 's_pid': context.project_id, 's_size': vol_ref['size'], 'd_consumed': _consumed(over), 'd_quota': quotas[over] }) raise exception.VolumeSizeExceedsAvailableQuota( requested=vol_ref['size'], consumed=_consumed(over), quota=quotas[over]) elif 'volumes' in over: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)") LOG.warning(msg, { 's_pid': context.project_id, 'd_consumed': _consumed(over) }) raise exception.VolumeLimitExceeded(allowed=quotas[over], name=over) try: donor_id = vol_ref['project_id'] reserve_opts = {'volumes': -1, 'gigabytes': -vol_ref.size} QUOTAS.add_volume_type_opts(context, reserve_opts, vol_ref.volume_type_id) donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, **reserve_opts) except Exception: donor_reservations = None LOG.exception( _LE("Failed to update quota donating volume" " transfer id %s"), transfer_id) try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_LI("Volume %s has been transferred."), volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) volume_utils.notify_about_volume_usage(context, vol_ref, "transfer.accept.end") return { 'id': transfer_id, 'display_name': transfer['display_name'], 'volume_id': vol_ref['id'] }
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, 'accept_transfer') transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer['salt'], auth_key) if crypt_hash != transfer['crypt_hash']: msg = (_("Attempt to transfer %s with invalid auth key.") % transfer_id) LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer['volume_id'] vol_ref = self.db.volume_get(context.elevated(), volume_id) try: reservations = QUOTAS.reserve(context, volumes=1, gigabytes=vol_ref['size']) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: msg = _("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG volume (%(d_consumed)dG of %(d_quota)dG " "already consumed)") LOG.warn(msg % {'s_pid': context.project_id, 's_size': vol_ref['size'], 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes']}) raise exception.VolumeSizeExceedsAvailableQuota( requested=vol_ref['size'], consumed=_consumed('gigabytes'), quota=quotas['gigabytes']) elif 'volumes' in overs: msg = _("Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)") LOG.warn(msg % {'s_pid': context.project_id, 'd_consumed': _consumed('volumes')}) raise exception.VolumeLimitExceeded(allowed=quotas['volumes']) try: donor_id = vol_ref['project_id'] donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, volumes=-1, gigabytes=-vol_ref['size']) except Exception: donor_reservations = None LOG.exception(_("Failed to update quota donating volume" "transfer id %s") % transfer_id) try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_("Volume %s has been transferred.") % volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) return {'id': transfer_id, 'display_name': transfer['display_name'], 'volume_id': vol_ref['id']}
def accept(self, context, transfer_id, auth_key): """Accept a volume that has been offered for transfer.""" # We must use an elevated context to see the volume that is still # owned by the donor. volume_api.check_policy(context, "accept_transfer") transfer = self.db.transfer_get(context.elevated(), transfer_id) crypt_hash = self._get_crypt_hash(transfer["salt"], auth_key) if crypt_hash != transfer["crypt_hash"]: msg = _("Attempt to transfer %s with invalid auth key.") % transfer_id LOG.error(msg) raise exception.InvalidAuthKey(reason=msg) volume_id = transfer["volume_id"] vol_ref = self.db.volume_get(context.elevated(), volume_id) try: reservations = QUOTAS.reserve(context, volumes=1, gigabytes=vol_ref["size"]) except exception.OverQuota as e: overs = e.kwargs["overs"] usages = e.kwargs["usages"] quotas = e.kwargs["quotas"] def _consumed(name): return usages[name]["reserved"] + usages[name]["in_use"] if "gigabytes" in overs: msg = _( "Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG volume (%(d_consumed)dG of %(d_quota)dG " "already consumed)" ) LOG.warn( msg % { "s_pid": context.project_id, "s_size": vol_ref["size"], "d_consumed": _consumed("gigabytes"), "d_quota": quotas["gigabytes"], } ) raise exception.VolumeSizeExceedsAvailableQuota( requested=vol_ref["size"], consumed=_consumed("gigabytes"), quota=quotas["gigabytes"] ) elif "volumes" in overs: msg = _( "Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)" ) LOG.warn(msg % {"s_pid": context.project_id, "d_consumed": _consumed("volumes")}) raise exception.VolumeLimitExceeded(allowed=quotas["volumes"]) try: donor_id = vol_ref["project_id"] donor_reservations = QUOTAS.reserve( context.elevated(), project_id=donor_id, volumes=-1, gigabytes=-vol_ref["size"] ) except Exception: donor_reservations = None LOG.exception(_LE("Failed to update quota donating volume" " transfer id %s") % transfer_id) try: # Transfer ownership of the volume now, must use an elevated # context. self.volume_api.accept_transfer(context, vol_ref, context.user_id, context.project_id) self.db.transfer_accept(context.elevated(), transfer_id, context.user_id, context.project_id) QUOTAS.commit(context, reservations) if donor_reservations: QUOTAS.commit(context, donor_reservations, project_id=donor_id) LOG.info(_LI("Volume %s has been transferred.") % volume_id) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) if donor_reservations: QUOTAS.rollback(context, donor_reservations, project_id=donor_id) vol_ref = self.db.volume_get(context, volume_id) return {"id": transfer_id, "display_name": transfer["display_name"], "volume_id": vol_ref["id"]}