Esempio n. 1
0
File: api.py Progetto: NetApp/cinder
    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']}
Esempio n. 2
0
 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
Esempio n. 3
0
    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"],
        }
Esempio n. 4
0
File: api.py Progetto: NetApp/cinder
 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
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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"]}
Esempio n. 8
0
    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")
Esempio n. 9
0
    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']
        }
Esempio n. 10
0
    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']
        }
Esempio n. 11
0
File: api.py Progetto: NetApp/cinder
 def get(self, context, transfer_id):
     volume_api.check_policy(context, 'get_transfer')
     rv = self.db.transfer_get(context, transfer_id)
     return dict(rv)
Esempio n. 12
0
File: api.py Progetto: NetApp/cinder
    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']}
Esempio n. 13
0
    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']}
Esempio n. 14
0
    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']
        }
Esempio n. 15
0
    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']}
Esempio n. 16
0
 def get(self, context, transfer_id):
     volume_api.check_policy(context, 'get_transfer')
     rv = self.db.transfer_get(context, transfer_id)
     return dict(rv)
Esempio n. 17
0
    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"]}