示例#1
0
 def create_volume(self, volume):
     LOG.debug('create_volume, volume %s.', volume['id'])
     volume_name = VOLUME_PREFIX + volume['id'][-12:]
     pool_name = volume_utils.extract_host(volume['host'], 'pool')
     ret = self._cmd.create_volume(
         volume_name,
         str(volume['size']),
         pool_name)
     if ret['key'] == 310:
         msg = _('Volume: %s with same name '
                 'already exists on the system.') % volume_name
         raise exception.VolumeBackendAPIException(data=msg)
     elif ret['key'] == 102:
         allow_size = 0
         for p in self._stats['pools']:
             if p['pool_name'] == pool_name:
                 allow_size = p['free_capacity_gb']
                 break
         raise exception.VolumeSizeExceedsLimit(size=int(volume['size']),
                                                limit=allow_size)
     elif ret['key'] == 307:
         raise exception.VolumeLimitExceeded(allowed=96,
                                             name=volume_name)
     elif ret['key'] == 308:
         raise exception.VolumeLimitExceeded(allowed=4096,
                                             name=volume_name)
     model_update = None
     return model_update
示例#2
0
    def execute(self, context, size, volume_type_id, group_snapshot,
                optional_args):
        try:
            values = {'per_volume_gigabytes': size}
            QUOTAS.limit_check(context,
                               project_id=context.project_id,
                               **values)
        except exception.OverQuota as e:
            quotas = e.kwargs['quotas']
            raise exception.VolumeSizeExceedsLimit(
                size=size, limit=quotas['per_volume_gigabytes'])

        try:
            if group_snapshot:
                reserve_opts = {'volumes': 1}
            else:
                reserve_opts = {'volumes': 1, 'gigabytes': size}
            if ('update_size' in optional_args
                    and optional_args['update_size']):
                reserve_opts.pop('volumes', None)
            QUOTAS.add_volume_type_opts(context, reserve_opts, volume_type_id)
            reservations = QUOTAS.reserve(context, **reserve_opts)
            return {
                'reservations': reservations,
            }
        except exception.OverQuota as e:
            quota_utils.process_reserve_over_quota(context,
                                                   e,
                                                   resource='volumes',
                                                   size=size)
示例#3
0
    def execute(self, context, size, volume_type_id, optional_args):
        try:
            values = {'per_volume_gigabytes': size}
            QUOTAS.limit_check(context,
                               project_id=context.project_id,
                               **values)
        except exception.OverQuota as e:
            quotas = e.kwargs['quotas']
            raise exception.VolumeSizeExceedsLimit(
                size=size, limit=quotas['per_volume_gigabytes'])

        try:
            reserve_opts = {'volumes': 1, 'gigabytes': size}
            QUOTAS.add_volume_type_opts(context, reserve_opts, volume_type_id)
            reservations = QUOTAS.reserve(context, **reserve_opts)
            return {
                'reservations': reservations,
            }
        except exception.OverQuota as e:
            overs = e.kwargs['overs']
            quotas = e.kwargs['quotas']
            usages = e.kwargs['usages']

            def _consumed(name):
                return usages[name]['reserved'] + usages[name]['in_use']

            def _is_over(name):
                for over in overs:
                    if name in over:
                        return True
                return False

            if _is_over('gigabytes'):
                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': size,
                        'd_consumed': _consumed('gigabytes'),
                        'd_quota': quotas['gigabytes']
                    })
                raise exception.VolumeSizeExceedsAvailableQuota(
                    requested=size,
                    consumed=_consumed('gigabytes'),
                    quota=quotas['gigabytes'])
            elif _is_over('volumes'):
                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('volumes')
                    })
                raise exception.VolumeLimitExceeded(allowed=quotas['volumes'])
            else:
                # If nothing was reraised, ensure we reraise the initial error
                raise
示例#4
0
 def extend_volume(self, volume, new_size):
     volume_name = self._convert_name(volume.name)
     ret = self._cmd.extend_volume(volume_name, int(new_size))
     if ret['key'] == 303:
         raise exception.VolumeNotFound(volume_id=volume_name)
     elif ret['key'] == 321:
         msg = _('Volume capacity shall not be '
                 'less than the current size %sG.') % volume['size']
         raise exception.VolumeBackendAPIException(data=msg)
     elif ret['key'] == 102:
         pool_name = volume_utils.extract_host(volume['host'], 'pool')
         allow_size = 0
         for p in self._stats['pools']:
             if p['pool_name'] == pool_name:
                 allow_size = p['free_capacity_gb']
                 break
         raise exception.VolumeSizeExceedsLimit(size=int(new_size),
                                                limit=allow_size)
     elif ret['key'] != 0:
         msg = (_('Failed to extend_volume %(vol)s to size %(size)s, '
                  'code=%(ret)s, error=%(msg)s.') % {
                      'vol': volume_name,
                      'size': new_size,
                      'ret': ret['key'],
                      'msg': ret['msg']
                  })
         raise exception.VolumeBackendAPIException(data=msg)
示例#5
0
 def create_volume(self, volume):
     LOG.debug('create_volume, volume %s.', volume['id'])
     volume_name = self._convert_name(volume.name)
     pool_name = volume_utils.extract_host(volume['host'], 'pool')
     ret = self._cmd.create_volume(volume_name, str(volume['size']),
                                   pool_name)
     if ret['key'] == 310:
         msg = _('Volume: %s with same name '
                 'already exists on the system.') % volume_name
         raise exception.VolumeBackendAPIException(data=msg)
     elif ret['key'] == 102:
         allow_size = 0
         for p in self._stats['pools']:
             if p['pool_name'] == pool_name:
                 allow_size = p['free_capacity_gb']
                 break
         raise exception.VolumeSizeExceedsLimit(size=int(volume['size']),
                                                limit=allow_size)
     elif ret['key'] == 307:
         raise exception.VolumeLimitExceeded(allowed=96, name=volume_name)
     elif ret['key'] == 308:
         raise exception.VolumeLimitExceeded(allowed=4096, name=volume_name)
     elif ret['key'] != 0:
         msg = (_('Failed to create_volume %(vol)s on pool %(pool)s, '
                  'code=%(ret)s, error=%(msg)s.') % {
                      'vol': volume_name,
                      'pool': pool_name,
                      'ret': ret['key'],
                      'msg': ret['msg']
                  })
         raise exception.VolumeBackendAPIException(data=msg)
     return None
示例#6
0
 def extend_volume(self, volume, new_size):
     volume_name = VOLUME_PREFIX + volume['id'][-12:]
     ret = self._cmd.extend_volume(volume_name, int(new_size))
     if ret['key'] == 303:
         raise exception.VolumeNotFound(volume_id=volume_name)
     elif ret['key'] == 321:
         msg = _('Volume capacity shall not be '
                 'less than the current size %sG.') % volume['size']
         raise exception.VolumeBackendAPIException(data=msg)
     elif ret['key'] == 102:
         pool_name = volume_utils.extract_host(volume['host'], 'pool')
         allow_size = 0
         for p in self._stats['pools']:
             if p['pool_name'] == pool_name:
                 allow_size = p['free_capacity_gb']
                 break
         raise exception.VolumeSizeExceedsLimit(size=int(new_size),
                                                limit=allow_size)
示例#7
0
    def execute(self, context, size, volume_type_id, optional_args):
        try:
            values = {'per_volume_gigabytes': size}
            QUOTAS.limit_check(context,
                               project_id=context.project_id,
                               **values)
        except exception.OverQuota as e:
            quotas = e.kwargs['quotas']
            raise exception.VolumeSizeExceedsLimit(
                size=size, limit=quotas['per_volume_gigabytes'])

        try:
            reserve_opts = {'volumes': 1, 'gigabytes': size}
            QUOTAS.add_volume_type_opts(context, reserve_opts, volume_type_id)
            reservations = QUOTAS.reserve(context, **reserve_opts)
            return {
                'reservations': reservations,
            }
        except exception.OverQuota as e:
            overs = e.kwargs['overs']
            quotas = e.kwargs['quotas']
            usages = e.kwargs['usages']

            def _consumed(name):
                usage = usages[name]
                return usage['reserved'] + usage['in_use'] + usage.get(
                    'allocated', 0)

            def _get_over(name):
                for over in overs:
                    if name in over:
                        return over
                return None

            over_name = _get_over('gigabytes')
            exceeded_vol_limit_name = _get_over('volumes')
            if over_name:
                # TODO(mc_nair): improve error message for child -1 limit
                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': size,
                        'd_consumed': _consumed(over_name),
                        'd_quota': quotas[over_name]
                    })
                raise exception.VolumeSizeExceedsAvailableQuota(
                    name=over_name,
                    requested=size,
                    consumed=_consumed(over_name),
                    quota=quotas[over_name])
            elif exceeded_vol_limit_name:
                msg = _LW("Quota %(s_name)s exceeded for %(s_pid)s, tried "
                          "to create volume (%(d_consumed)d volume(s) "
                          "already consumed).")
                LOG.warning(
                    msg, {
                        's_name': exceeded_vol_limit_name,
                        's_pid': context.project_id,
                        'd_consumed': _consumed(exceeded_vol_limit_name)
                    })
                # TODO(mc_nair): improve error message for child -1 limit
                raise exception.VolumeLimitExceeded(
                    allowed=quotas[exceeded_vol_limit_name],
                    name=exceeded_vol_limit_name)
            else:
                # If nothing was reraised, ensure we reraise the initial error
                raise
示例#8
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.
        context.authorize(policy.ACCEPT_POLICY)
        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)

        snap_res = None
        snap_donor_res = None
        if transfer['no_snapshots'] is False:
            snapshots = objects.SnapshotList.get_all_for_volume(
                context.elevated(), volume_id)
            volume_type_id = vol_ref.volume_type_id
            snap_res, snap_donor_res = self._handle_snapshot_quota(
                context, snapshots, volume_type_id, vol_ref['project_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,
                                            transfer['no_snapshots'])
            self.db.transfer_accept(context.elevated(), transfer_id,
                                    context.user_id, context.project_id,
                                    transfer['no_snapshots'])
            QUOTAS.commit(context, reservations)
            if snap_res:
                QUOTAS.commit(context, snap_res)
            if donor_reservations:
                QUOTAS.commit(context, donor_reservations, project_id=donor_id)
            if snap_donor_res:
                QUOTAS.commit(context, snap_donor_res, 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 snap_res:
                    QUOTAS.rollback(context, snap_res)
                if donor_reservations:
                    QUOTAS.rollback(context,
                                    donor_reservations,
                                    project_id=donor_id)
                if snap_donor_res:
                    QUOTAS.rollback(context,
                                    snap_donor_res,
                                    project_id=donor_id)

        vol_ref = objects.Volume.get_by_id(context.elevated(), 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']
        }