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
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
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
def get_volume_type_reservation(ctxt, volume, type_id, reserve_vol_type_only=False): from cinder import quota QUOTAS = quota.QUOTAS # Reserve quotas for the given volume type try: reserve_opts = {'volumes': 1, 'gigabytes': volume['size']} QUOTAS.add_volume_type_opts(ctxt, reserve_opts, type_id) # If reserve_vol_type_only is True, just reserve volume_type quota, # not volume quota. if reserve_vol_type_only: reserve_opts.pop('volumes') reserve_opts.pop('gigabytes') # Note that usually the project_id on the volume will be the same as # the project_id in the context. But, if they are different then the # reservations must be recorded against the project_id that owns the # volume. project_id = volume['project_id'] reservations = QUOTAS.reserve(ctxt, project_id=project_id, **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: s_size = volume['size'] d_quota = quotas[over] d_consumed = _consumed(over) LOG.warning( _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG volume - (%(d_consumed)dG of " "%(d_quota)dG already consumed)"), { 's_pid': ctxt.project_id, 's_size': s_size, 'd_consumed': d_consumed, 'd_quota': d_quota }) raise exception.VolumeSizeExceedsAvailableQuota( requested=s_size, quota=d_quota, consumed=d_consumed) elif 'volumes' in over: LOG.warning( _LW("Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)"), { 's_pid': ctxt.project_id, 'd_consumed': _consumed(over) }) raise exception.VolumeLimitExceeded(allowed=quotas[over]) return reservations
def get_volume_type_reservation(ctxt, volume, type_id): # Reserve quotas for the given volume type try: reserve_opts = {'volumes': 1, 'gigabytes': volume['size']} QUOTAS.add_volume_type_opts(ctxt, reserve_opts, type_id) reservations = QUOTAS.reserve(ctxt, **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: s_size = volume['size'] d_quota = quotas[over] d_consumed = _consumed(over) 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': ctxt.project_id, 's_size': s_size, 'd_consumed': d_consumed, 'd_quota': d_quota }) raise exception.VolumeSizeExceedsAvailableQuota( requested=s_size, quota=d_quota, consumed=d_consumed) elif 'volumes' in over: msg = _("Quota exceeded for %(s_pid)s, tried to create " "volume (%(d_consumed)d volumes " "already consumed)") LOG.warn(msg % { 's_pid': ctxt.project_id, 'd_consumed': _consumed(over) }) raise exception.VolumeLimitExceeded(allowed=quotas[over]) return reservations
def fake_transfer_api_accept_throwing_VolumeLimitExceeded( cls, context, transfer, volume_id): raise exception.VolumeLimitExceeded(allowed=1)
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 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
def fake_backup_api_restore_throwing_VolumeLimitExceeded( cls, context, backup_id, volume_id): raise exception.VolumeLimitExceeded(allowed=1)
def create(self, context, size, name, description, snapshot=None, image_id=None, volume_type=None, metadata=None, availability_zone=None): check_policy(context, 'create') if snapshot is not None: if snapshot['status'] != "available": msg = _("status must be available") raise exception.InvalidSnapshot(reason=msg) if not size: size = snapshot['volume_size'] snapshot_id = snapshot['id'] else: snapshot_id = None def as_int(s): try: return int(s) except ValueError: return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = (_("Volume size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, volumes=1, gigabytes=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']) pid = context.project_id if 'gigabytes' in overs: consumed = _consumed('gigabytes') quota = quotas['gigabytes'] LOG.warn(_("Quota exceeded for %(pid)s, tried to create " "%(size)sG volume (%(consumed)dG of %(quota)dG " "already consumed)") % locals()) raise exception.VolumeSizeExceedsAvailableQuota() elif 'volumes' in overs: consumed = _consumed('volumes') LOG.warn(_("Quota exceeded for %(pid)s, tried to create " "volume (%(consumed)d volumes already consumed)") % locals()) raise exception.VolumeLimitExceeded(allowed=quotas['volumes']) if image_id: # check image existence image_meta = self.image_service.show(context, image_id) image_size_in_gb = (int(image_meta['size']) + GB - 1) / GB #check image size is not larger than volume size. if image_size_in_gb > size: msg = _('Size of specified image is larger than volume size.') raise exception.InvalidInput(reason=msg) if availability_zone is None: availability_zone = FLAGS.storage_availability_zone if volume_type is None: volume_type_id = None else: volume_type_id = volume_type.get('id', None) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'availability_zone': availability_zone, 'status': "creating", 'attach_status': "detached", 'display_name': name, 'display_description': description, 'volume_type_id': volume_type_id, 'metadata': metadata, } volume = self.db.volume_create(context, options) QUOTAS.commit(context, reservations) self._cast_create_volume(context, volume['id'], snapshot_id, image_id) return volume
def _create_cg_from_source_cg(self, context, group, source_cgid): try: source_cg = objects.ConsistencyGroup.get_by_id( context, source_cgid) source_vols = self.db.volume_get_all_by_group( context, source_cg.id) if not source_vols: msg = _("Source CG is empty. No consistency group " "will be created.") raise exception.InvalidConsistencyGroup(reason=msg) try: values = {'volumes': len(source_vols)} QUOTAS.limit_check(context, project_id=context.project_id, **values) except exception.OverQuota as e: group.destroy() quotas = e.kwargs['quotas'] raise exception.VolumeLimitExceeded(allowed=e.kwargs['overs'], limit=quotas['volumes']) for source_vol in source_vols: kwargs = {} kwargs['availability_zone'] = group.availability_zone kwargs['source_cg'] = source_cg kwargs['consistencygroup'] = group kwargs['source_volume'] = source_vol volume_type_id = source_vol.get('volume_type_id') if volume_type_id: kwargs['volume_type'] = ( objects.VolumeType.get_by_name_or_id( context, volume_type_id)) # Since source_cg is passed in, the following call will # create a db entry for the volume, but will not call the # volume manager to create a real volume in the backend yet. # If error happens, taskflow will handle rollback of quota # and removal of volume entry in the db. try: self.volume_api.create(context, source_vol['size'], None, None, **kwargs) except exception.CinderException: with excutils.save_and_reraise_exception(): LOG.error( "Error occurred when creating cloned " "volume in the process of creating " "consistency group %(group)s from " "source CG %(source_cg)s.", { 'group': group.id, 'source_cg': source_cg.id }) except Exception: with excutils.save_and_reraise_exception(): try: new_vols = self.db.volume_get_all_by_group( context, group.id) for vol in new_vols: self.volume_api.delete(context, vol, force=True) group.destroy() finally: LOG.error( "Error occurred when creating consistency " "group %(group)s from source CG " "%(source_cg)s.", { 'group': group.id, 'source_cg': source_cg.id }) volumes = self.db.volume_get_all_by_group(context, group.id) for vol in volumes: # Update the host field for the volume. self.db.volume_update(context, vol['id'], {'host': group.host}) self.volume_rpcapi.create_consistencygroup_from_src( context, group, None, source_cg)
def create(self, context, size, name, description, snapshot=None, image_id=None, volume_type=None, metadata=None, availability_zone=None, source_volume=None, scheduler_hints=None): exclusive_options = (snapshot, image_id, source_volume) exclusive_options_set = sum(1 for option in exclusive_options if option is not None) if exclusive_options_set > 1: msg = (_("May specify only one of snapshot, imageRef " "or source volume")) raise exception.InvalidInput(reason=msg) check_policy(context, 'create') if snapshot is not None: if snapshot['status'] != "available": msg = _("status must be available") raise exception.InvalidSnapshot(reason=msg) if not size: size = snapshot['volume_size'] elif size < snapshot['volume_size']: msg = _("Volume size cannot be lesser than" " the Snapshot size") raise exception.InvalidInput(reason=msg) snapshot_id = snapshot['id'] else: snapshot_id = None if source_volume is not None: if source_volume['status'] == "error": msg = _("Unable to clone volumes that are in an error state") raise exception.InvalidSourceVolume(reason=msg) if not size: size = source_volume['size'] else: if size < source_volume['size']: msg = _("Clones currently must be " ">= original volume size.") raise exception.InvalidInput(reason=msg) source_volid = source_volume['id'] else: source_volid = None def as_int(s): try: return int(s) except (ValueError, TypeError): return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = ( _("Volume size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) if (image_id and not (source_volume or snapshot)): # check image existence image_meta = self.image_service.show(context, image_id) image_size_in_gb = (int(image_meta['size']) + GB - 1) / GB #check image size is not larger than volume size. if image_size_in_gb > size: msg = _('Size of specified image is larger than volume size.') raise exception.InvalidInput(reason=msg) # Check image minDisk requirement is met for the particular volume if size < image_meta.get('min_disk', 0): msg = _('Image minDisk size is larger than the volume size.') raise exception.InvalidInput(reason=msg) if availability_zone is None: if snapshot is not None: availability_zone = snapshot['volume']['availability_zone'] elif source_volume is not None: availability_zone = source_volume['availability_zone'] else: availability_zone = CONF.storage_availability_zone else: self._check_availabilty_zone(availability_zone) if CONF.cloned_volume_same_az: if (snapshot and snapshot['volume']['availability_zone'] != availability_zone): msg = _("Volume must be in the same " "availability zone as the snapshot") raise exception.InvalidInput(reason=msg) elif source_volume and \ source_volume['availability_zone'] != availability_zone: msg = _("Volume must be in the same " "availability zone as the source volume") raise exception.InvalidInput(reason=msg) if not volume_type and not source_volume: volume_type = volume_types.get_default_volume_type() if not volume_type and source_volume: volume_type_id = source_volume['volume_type_id'] else: volume_type_id = volume_type.get('id') try: reserve_opts = {'volumes': 1, 'gigabytes': size} QUOTAS.add_volume_type_opts(context, reserve_opts, 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 = _("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': size, 'd_consumed': _consumed(over), 'd_quota': quotas[over] }) raise exception.VolumeSizeExceedsAvailableQuota() elif 'volumes' in over: 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(over) }) raise exception.VolumeLimitExceeded(allowed=quotas[over]) self._check_metadata_properties(context, metadata) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'availability_zone': availability_zone, 'status': "creating", 'attach_status': "detached", 'display_name': name, 'display_description': description, 'volume_type_id': volume_type_id, 'metadata': metadata, 'source_volid': source_volid } try: volume = self.db.volume_create(context, options) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.volume_destroy(context, volume['id']) finally: QUOTAS.rollback(context, reservations) request_spec = { 'volume_properties': options, 'volume_type': volume_type, 'volume_id': volume['id'], 'snapshot_id': volume['snapshot_id'], 'image_id': image_id, 'source_volid': volume['source_volid'] } if scheduler_hints: filter_properties = {'scheduler_hints': scheduler_hints} else: filter_properties = {} self._cast_create_volume(context, request_spec, filter_properties) return volume
def create(self, context, size, name, description, snapshot=None, image_id=None, volume_type=None, metadata=None, availability_zone=None, source_volume=None): if ((snapshot is not None) and (source_volume is not None)): msg = (_("May specify either snapshot, " "or src volume but not both!")) raise exception.InvalidInput(reason=msg) check_policy(context, 'create') if snapshot is not None: if snapshot['status'] != "available": msg = _("status must be available") raise exception.InvalidSnapshot(reason=msg) if not size: size = snapshot['volume_size'] snapshot_id = snapshot['id'] else: snapshot_id = None if source_volume is not None: if source_volume['status'] == "error": msg = _("Unable to clone volumes that are in an error state") raise exception.InvalidSourceVolume(reason=msg) if not size: size = source_volume['size'] else: if size < source_volume['size']: msg = _("Clones currently must be " ">= original volume size.") raise exception.InvalidInput(reason=msg) source_volid = source_volume['id'] else: source_volid = None def as_int(s): try: return int(s) except (ValueError, TypeError): return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = ( _("Volume size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) if (image_id and not (source_volume or snapshot)): # check image existence image_meta = self.image_service.show(context, image_id) image_size_in_gb = (int(image_meta['size']) + GB - 1) / GB #check image size is not larger than volume size. if image_size_in_gb > size: msg = _('Size of specified image is larger than volume size.') raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, volumes=1, gigabytes=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': 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']) if availability_zone is None: availability_zone = FLAGS.storage_availability_zone if not volume_type and not source_volume: volume_type = volume_types.get_default_volume_type() if not volume_type and source_volume: volume_type_id = source_volume['volume_type_id'] else: volume_type_id = volume_type.get('id') self._check_metadata_properties(context, metadata) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'availability_zone': availability_zone, 'status': "creating", 'attach_status': "detached", 'display_name': name, 'display_description': description, 'volume_type_id': volume_type_id, 'metadata': metadata, 'source_volid': source_volid } try: volume = self.db.volume_create(context, options) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.volume_destroy(context, volume['id']) finally: QUOTAS.rollback(context, reservations) request_spec = { 'volume_properties': options, 'volume_type': volume_type, 'volume_id': volume['id'], 'snapshot_id': volume['snapshot_id'], 'image_id': image_id, 'source_volid': volume['source_volid'] } filter_properties = {} self._cast_create_volume(context, request_spec, filter_properties) return volume
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'] }