コード例 #1
0
ファイル: volumes.py プロジェクト: lubidl0/cinder-1
    def update(self, req, id, body):
        """Update a volume."""
        context = req.environ['cinder.context']
        update_dict = body['volume']

        self.validate_name_and_description(update_dict, check_length=False)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in update_dict:
            update_dict['display_name'] = update_dict.pop('name')

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if 'description' in update_dict:
            update_dict['display_description'] = update_dict.pop('description')

        # Not found and Invalid exceptions will be handled at the wsgi level
        try:
            volume = self.volume_api.get(context, id, viewable_admin_meta=True)
            volume_utils.notify_about_volume_usage(context, volume,
                                                   'update.start')
            self.volume_api.update(context, volume, update_dict)
        except exception.InvalidVolumeMetadataSize as error:
            raise webob.exc.HTTPRequestEntityTooLarge(explanation=error.msg)

        volume.update(update_dict)

        api_utils.add_visible_admin_metadata(volume)

        volume_utils.notify_about_volume_usage(context, volume, 'update.end')

        return self._view_builder.detail(req, volume)
コード例 #2
0
    def create(self, context, volume_id, display_name, no_snapshots=False):
        """Creates an entry in the transfers table."""
        LOG.info("Generating transfer record for volume %s", volume_id)
        volume_ref = objects.Volume.get_by_id(context, volume_id)
        context.authorize(policy.CREATE_POLICY, target_obj=volume_ref)
        if volume_ref['status'] != "available":
            raise exception.InvalidVolume(reason=_("status must be available"))
        if volume_ref['encryption_key_id'] is not None:
            raise exception.InvalidVolume(
                reason=_("transferring encrypted volume is not supported"))

        if not no_snapshots:
            snapshots = self.db.snapshot_get_all_for_volume(context, volume_id)
            for snapshot in snapshots:
                if snapshot['status'] != "available":
                    msg = _("snapshot: %s status must be "
                            "available") % snapshot['id']
                    raise exception.InvalidSnapshot(reason=msg)
                if snapshot.get('encryption_key_id'):
                    msg = _("snapshot: %s encrypted snapshots cannot be "
                            "transferred") % snapshot['id']
                    raise exception.InvalidSnapshot(reason=msg)

        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,
            'no_snapshots': no_snapshots,
            'source_project_id': volume_ref['project_id']
        }

        try:
            transfer = self.db.transfer_create(context, transfer_rec)
        except Exception:
            LOG.error("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'],
            'no_snapshots': transfer['no_snapshots'],
            'source_project_id': transfer['source_project_id'],
            'destination_project_id': transfer['destination_project_id'],
            'accepted': transfer['accepted']
        }
コード例 #3
0
    def delete(self, context, transfer_id):
        """Make the RPC call to delete a volume transfer."""
        transfer = self.db.transfer_get(context, transfer_id)

        volume_ref = objects.Volume.get_by_id(context, transfer.volume_id)
        context.authorize(policy.DELETE_POLICY, target_obj=volume_ref)
        volume_utils.notify_about_volume_usage(context, volume_ref,
                                               "transfer.delete.start")
        if volume_ref['status'] != 'awaiting-transfer':
            LOG.error("Volume in unexpected state")
        self.db.transfer_destroy(context, transfer_id)
        volume_utils.notify_about_volume_usage(context, volume_ref,
                                               "transfer.delete.end")
コード例 #4
0
 def complete(self, req, id, body):
     """Mark a volume attachment process as completed (in-use)."""
     context = req.environ['cinder.context']
     attachment_ref = (objects.VolumeAttachment.get_by_id(context, id))
     volume_ref = objects.Volume.get_by_id(context,
                                           attachment_ref.volume_id)
     context.authorize(attachment_policy.COMPLETE_POLICY,
                       target_obj=attachment_ref)
     attachment_ref.update(
         {'attach_status': fields.VolumeAttachStatus.ATTACHED})
     attachment_ref.save()
     volume_ref.update({'status': 'in-use', 'attach_status': 'attached'})
     volume_ref.save()
     volume_utils.notify_about_volume_usage(context, volume_ref,
                                            "attach.end")
コード例 #5
0
 def _notify_reset_status(self, context, id, message):
     volume = objects.Volume.get_by_id(context, id)
     volume_utils.notify_about_volume_usage(context, volume, message)
コード例 #6
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']}