Exemplo n.º 1
0
    def _verify_if_non_public_share_type(self, context, share_type_id):
        try:
            share_type = share_types.get_share_type(context, share_type_id)

            if share_type['is_public']:
                msg = _("Type access modification is not applicable to "
                        "public share type.")
                raise webob.exc.HTTPConflict(explanation=msg)

        except exception.ShareTypeNotFound as err:
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
Exemplo n.º 2
0
    def show(self, req, id):
        """Return a single share type item."""
        context = req.environ['manila.context']
        try:
            share_type = share_types.get_share_type(context, id)
        except exception.NotFound:
            msg = _("Share type not found.")
            raise exc.HTTPNotFound(explanation=msg)

        share_type['id'] = six.text_type(share_type['id'])
        req.cache_db_share_type(share_type)
        return self._view_builder.show(req, share_type)
Exemplo n.º 3
0
    def _show_share_type_details(self, context, id):
        share_type = share_types.get_share_type(context, id)
        required_extra_specs = {}
        try:
            required_extra_specs = share_types.get_valid_required_extra_specs(
                share_type['extra_specs'])
        except exception.InvalidExtraSpec:
            LOG.exception('Share type %(share_type_id)s has invalid required'
                          ' extra specs.', {'share_type_id': id})

        share_type['required_extra_specs'] = required_extra_specs
        return share_type
Exemplo n.º 4
0
    def share_type_access(self, req, id):
        context = req.environ['manila.context']

        try:
            share_type = share_types.get_share_type(
                context, id, expected_fields=['projects'])
        except exception.ShareTypeNotFound:
            explanation = _("Share type %s not found.") % id
            raise webob.exc.HTTPNotFound(explanation=explanation)

        if share_type['is_public']:
            expl = _("Access list not available for public share types.")
            raise webob.exc.HTTPNotFound(explanation=expl)

        return self._view_builder.share_type_access(req, share_type)
Exemplo n.º 5
0
    def index(self, req, type_id):
        context = req.environ['manila.context']
        authorize(context)

        try:
            share_type = share_types.get_share_type(
                context, type_id, expected_fields=['projects'])
        except exception.ShareTypeNotFound:
            explanation = _("Share type %s not found.") % type_id
            raise webob.exc.HTTPNotFound(explanation=explanation)

        if share_type['is_public']:
            expl = _("Access list not available for public share types.")
            raise webob.exc.HTTPNotFound(explanation=expl)

        return _marshall_share_type_access(share_type)
Exemplo n.º 6
0
    def share_type_access(self, req, id):
        context = req.environ['manila.context']

        try:
            share_type = share_types.get_share_type(
                context, id, expected_fields=['projects'])
        except exception.ShareTypeNotFound:
            explanation = _("Share type %s not found.") % id
            raise webob.exc.HTTPNotFound(explanation=explanation)

        if share_type['is_public']:
            expl = _("Access list not available for public share types.")
            raise webob.exc.HTTPNotFound(explanation=expl)

        # TODO(vponomaryov): move to views.
        rval = []
        for project_id in share_type['projects']:
            rval.append(
                {'share_type_id': share_type['id'], 'project_id': project_id}
            )
        return {'share_type_access': rval}
Exemplo n.º 7
0
    def _addProjectAccess(self, req, id, body):
        context = req.environ['manila.context']
        authorize(context, action="addProjectAccess")
        self._check_body(body, 'addProjectAccess')
        project = body['addProjectAccess']['project']

        try:
            share_type = share_types.get_share_type(context, id)

            if share_type['is_public']:
                msg = _("You cannot add project to public share_type.")
                raise webob.exc.HTTPForbidden(explanation=msg)

        except exception.ShareTypeNotFound as err:
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))

        try:
            share_types.add_share_type_access(context, id, project)
        except exception.ShareTypeAccessExists as err:
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))

        return webob.Response(status_int=202)
Exemplo n.º 8
0
    def _delete(self, req, id):
        """Deletes an existing share type."""
        context = req.environ['manila.context']

        try:
            share_type = share_types.get_share_type(context, id)
            share_types.destroy(context, share_type['id'])
            notifier_info = dict(share_types=share_type)
            rpc.get_notifier('shareType').info(
                context, 'share_type.delete', notifier_info)
        except exception.ShareTypeInUse as err:
            notifier_err = dict(id=id, error_message=six.text_type(err))
            self._notify_share_type_error(context, 'share_type.delete',
                                          notifier_err)
            msg = 'Target share type is still in use.'
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.NotFound as err:
            notifier_err = dict(id=id, error_message=six.text_type(err))
            self._notify_share_type_error(context, 'share_type.delete',
                                          notifier_err)

            raise webob.exc.HTTPNotFound()

        return webob.Response(status_int=http_client.ACCEPTED)
Exemplo n.º 9
0
    def _create(self, req, body):
        """Creates a new share."""
        context = req.environ['manila.context']

        if not self.is_valid_body(body, 'share'):
            raise exc.HTTPUnprocessableEntity()

        share = body['share']

        # NOTE(rushiagr): Manila API allows 'name' instead of 'display_name'.
        if share.get('name'):
            share['display_name'] = share.get('name')
            del share['name']

        # NOTE(rushiagr): Manila API allows 'description' instead of
        #                 'display_description'.
        if share.get('description'):
            share['display_description'] = share.get('description')
            del share['description']

        size = share['size']
        share_proto = share['share_proto'].upper()

        msg = (_LI("Create %(share_proto)s share of %(size)s GB") %
               {'share_proto': share_proto, 'size': size})
        LOG.info(msg, context=context)

        availability_zone = share.get('availability_zone')

        if availability_zone:
            try:
                db.availability_zone_get(context, availability_zone)
            except exception.AvailabilityZoneNotFound as e:
                raise exc.HTTPNotFound(explanation=six.text_type(e))

        kwargs = {
            'availability_zone': availability_zone,
            'metadata': share.get('metadata'),
            'is_public': share.get('is_public', False),
            'consistency_group_id': share.get('consistency_group_id')
        }

        snapshot_id = share.get('snapshot_id')
        if snapshot_id:
            snapshot = self.share_api.get_snapshot(context, snapshot_id)
        else:
            snapshot = None

        kwargs['snapshot'] = snapshot

        share_network_id = share.get('share_network_id')

        if snapshot:
            # Need to check that share_network_id from snapshot's
            # parents share equals to share_network_id from args.
            # If share_network_id is empty than update it with
            # share_network_id of parent share.
            parent_share = self.share_api.get(context, snapshot['share_id'])
            parent_share_net_id = parent_share['share_network_id']
            if share_network_id:
                if share_network_id != parent_share_net_id:
                    msg = "Share network ID should be the same as snapshot's" \
                          " parent share's or empty"
                    raise exc.HTTPBadRequest(explanation=msg)
            elif parent_share_net_id:
                share_network_id = parent_share_net_id

        if share_network_id:
            try:
                self.share_api.get_share_network(
                    context,
                    share_network_id)
            except exception.ShareNetworkNotFound as e:
                raise exc.HTTPNotFound(explanation=six.text_type(e))
            kwargs['share_network_id'] = share_network_id

        display_name = share.get('display_name')
        display_description = share.get('display_description')

        if 'share_type' in share and 'volume_type' in share:
            msg = 'Cannot specify both share_type and volume_type'
            raise exc.HTTPBadRequest(explanation=msg)
        req_share_type = share.get('share_type', share.get('volume_type'))

        if req_share_type:
            try:
                if not uuidutils.is_uuid_like(req_share_type):
                    kwargs['share_type'] = \
                        share_types.get_share_type_by_name(
                            context, req_share_type)
                else:
                    kwargs['share_type'] = share_types.get_share_type(
                        context, req_share_type)
            except exception.ShareTypeNotFound:
                msg = _("Share type not found.")
                raise exc.HTTPNotFound(explanation=msg)
        elif not snapshot:
            def_share_type = share_types.get_default_share_type()
            if def_share_type:
                kwargs['share_type'] = def_share_type

        new_share = self.share_api.create(context,
                                          share_proto,
                                          size,
                                          display_name,
                                          display_description,
                                          **kwargs)

        return self._view_builder.detail(req, dict(six.iteritems(new_share)))
Exemplo n.º 10
0
    def create(self, context, share_proto, size, name, description,
               snapshot=None, availability_zone=None, metadata=None,
               share_network_id=None, share_type=None, is_public=False):
        """Create new share."""
        policy.check_policy(context, 'share', 'create')

        self._check_metadata_properties(context, metadata)

        if snapshot is not None:
            if snapshot['status'] != constants.STATUS_AVAILABLE:
                msg = _("status must be '%s'") % constants.STATUS_AVAILABLE
                raise exception.InvalidShareSnapshot(reason=msg)
            if not size:
                size = snapshot['size']

            snapshot_id = snapshot['id']
        else:
            snapshot_id = 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 = (_("Share size '%s' must be an integer and greater than 0")
                   % size)
            raise exception.InvalidInput(reason=msg)

        if snapshot and size < snapshot['size']:
            msg = (_("Share size '%s' must be equal or greater "
                     "than snapshot size") % size)
            raise exception.InvalidInput(reason=msg)

        if snapshot is None:
            share_type_id = share_type['id'] if share_type else None
        else:
            source_share = self.db.share_get(context, snapshot['share_id'])
            if share_type is None:
                share_type_id = source_share['share_type_id']
                if share_type_id is not None:
                    share_type = share_types.get_share_type(context,
                                                            share_type_id)
            else:
                share_type_id = share_type['id']
                if share_type_id != source_share['share_type_id']:
                    msg = _("Invalid share type specified: the requested "
                            "share type must match the type of the source "
                            "share. If a share type is not specified when "
                            "requesting a new share from a snapshot, the "
                            "share type of the source share will be applied "
                            "to the new share.")
                    raise exception.InvalidInput(reason=msg)

        supported_share_protocols = (
            proto.upper() for proto in CONF.enabled_share_protocols)
        if not (share_proto and
                share_proto.upper() in supported_share_protocols):
            msg = (_("Invalid share protocol provided: %(provided)s. "
                     "It is either disabled or unsupported. Available "
                     "protocols: %(supported)s") % dict(
                         provided=share_proto,
                         supported=CONF.enabled_share_protocols))
            raise exception.InvalidInput(reason=msg)

        try:
            reservations = QUOTAS.reserve(context, shares=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:
                LOG.warn(_LW("Quota exceeded for %(s_pid)s, tried to create "
                             "%(s_size)sG share (%(d_consumed)dG of "
                             "%(d_quota)dG already consumed)"), {
                                 's_pid': context.project_id,
                                 's_size': size,
                                 'd_consumed': _consumed('gigabytes'),
                                 'd_quota': quotas['gigabytes']})
                raise exception.ShareSizeExceedsAvailableQuota()
            elif 'shares' in overs:
                LOG.warn(_LW("Quota exceeded for %(s_pid)s, tried to create "
                             "share (%(d_consumed)d shares "
                             "already consumed)"), {
                                 's_pid': context.project_id,
                                 'd_consumed': _consumed('shares')})
                raise exception.ShareLimitExceeded(allowed=quotas['shares'])

        if availability_zone is None:
            availability_zone = CONF.storage_availability_zone

        try:
            is_public = strutils.bool_from_string(is_public, strict=True)
        except ValueError as e:
            raise exception.InvalidParameterValue(six.text_type(e))

        options = {'size': size,
                   'user_id': context.user_id,
                   'project_id': context.project_id,
                   'snapshot_id': snapshot_id,
                   'share_network_id': share_network_id,
                   'availability_zone': availability_zone,
                   'metadata': metadata,
                   'status': constants.STATUS_CREATING,
                   'scheduled_at': timeutils.utcnow(),
                   'display_name': name,
                   'display_description': description,
                   'share_proto': share_proto,
                   'share_type_id': share_type_id,
                   'is_public': is_public,
                   }

        try:
            share = self.db.share_create(context, options)
            QUOTAS.commit(context, reservations)
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    self.db.share_delete(context, share['id'])
                finally:
                    QUOTAS.rollback(context, reservations)

        request_spec = {
            'share_properties': options,
            'share_proto': share_proto,
            'share_id': share['id'],
            'snapshot_id': snapshot_id,
            'share_type': share_type,
        }
        filter_properties = {}

        if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot):
            # Shares from snapshots with restriction - source host only.
            # It is common situation for different types of backends.
            host = snapshot['share']['host']
            share = self.db.share_update(context, share['id'], {'host': host})
            self.share_rpcapi.create_share(
                context,
                share,
                host,
                request_spec=request_spec,
                filter_properties=filter_properties,
                snapshot_id=snapshot_id,
            )
        else:
            # Shares from scratch and from snapshots when source host is not
            # the only allowed, it is possible, for example, in multibackend
            # installation with Generic drivers only.
            self.scheduler_rpcapi.create_share(
                context,
                CONF.share_topic,
                share['id'],
                snapshot_id,
                request_spec=request_spec,
                filter_properties=filter_properties,
            )

        return share
Exemplo n.º 11
0
 def _check_type(self, context, type_id):
     try:
         share_types.get_share_type(context, type_id)
     except exception.NotFound as ex:
         raise webob.exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 12
0
    def create(self,
               context,
               share_proto,
               size,
               name,
               description,
               snapshot=None,
               availability_zone=None,
               metadata=None,
               share_network_id=None,
               share_type=None,
               is_public=False):
        """Create new share."""
        policy.check_policy(context, 'share', 'create')

        self._check_metadata_properties(context, metadata)

        if snapshot is not None:
            if snapshot['status'] != 'available':
                msg = _("status must be 'available'")
                raise exception.InvalidShareSnapshot(reason=msg)
            if not size:
                size = snapshot['size']

            snapshot_id = snapshot['id']
        else:
            snapshot_id = 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 = (_("Share size '%s' must be an integer and greater than 0") %
                   size)
            raise exception.InvalidInput(reason=msg)

        if snapshot and size < snapshot['size']:
            msg = (_("Share size '%s' must be equal or greater "
                     "than snapshot size") % size)
            raise exception.InvalidInput(reason=msg)

        if snapshot is None:
            share_type_id = share_type['id'] if share_type else None
        else:
            source_share = self.db.share_get(context, snapshot['share_id'])
            if share_type is None:
                share_type_id = source_share['share_type_id']
                if share_type_id is not None:
                    share_type = share_types.get_share_type(
                        context, share_type_id)
            else:
                share_type_id = share_type['id']
                if share_type_id != source_share['share_type_id']:
                    msg = _("Invalid share type specified: the requested "
                            "share type must match the type of the source "
                            "share. If a share type is not specified when "
                            "requesting a new share from a snapshot, the "
                            "share type of the source share will be applied "
                            "to the new share.")
                    raise exception.InvalidInput(reason=msg)

        supported_share_protocols = (proto.upper()
                                     for proto in CONF.enabled_share_protocols)
        if not (share_proto
                and share_proto.upper() in supported_share_protocols):
            msg = (_("Invalid share protocol provided: %(provided)s. "
                     "It is either disabled or unsupported. Available "
                     "protocols: %(supported)s") %
                   dict(provided=share_proto,
                        supported=CONF.enabled_share_protocols))
            raise exception.InvalidInput(reason=msg)

        try:
            reservations = QUOTAS.reserve(context, shares=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:
                LOG.warn(
                    _LW("Quota exceeded for %(s_pid)s, tried to create "
                        "%(s_size)sG share (%(d_consumed)dG of "
                        "%(d_quota)dG already consumed)"), {
                            's_pid': context.project_id,
                            's_size': size,
                            'd_consumed': _consumed('gigabytes'),
                            'd_quota': quotas['gigabytes']
                        })
                raise exception.ShareSizeExceedsAvailableQuota()
            elif 'shares' in overs:
                LOG.warn(
                    _LW("Quota exceeded for %(s_pid)s, tried to create "
                        "share (%(d_consumed)d shares "
                        "already consumed)"), {
                            's_pid': context.project_id,
                            'd_consumed': _consumed('shares')
                        })
                raise exception.ShareLimitExceeded(allowed=quotas['shares'])

        if availability_zone is None:
            availability_zone = CONF.storage_availability_zone

        try:
            is_public = strutils.bool_from_string(is_public, strict=True)
        except ValueError as e:
            raise exception.InvalidParameterValue(e.message)

        options = {
            'size': size,
            'user_id': context.user_id,
            'project_id': context.project_id,
            'snapshot_id': snapshot_id,
            'share_network_id': share_network_id,
            'availability_zone': availability_zone,
            'metadata': metadata,
            'status': "creating",
            'scheduled_at': timeutils.utcnow(),
            'display_name': name,
            'display_description': description,
            'share_proto': share_proto,
            'share_type_id': share_type_id,
            'is_public': is_public,
        }

        try:
            share = self.db.share_create(context, options)
            QUOTAS.commit(context, reservations)
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    self.db.share_delete(context, share['id'])
                finally:
                    QUOTAS.rollback(context, reservations)

        request_spec = {
            'share_properties': options,
            'share_proto': share_proto,
            'share_id': share['id'],
            'snapshot_id': snapshot_id,
            'share_type': share_type,
        }
        filter_properties = {}

        if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot):
            # Shares from snapshots with restriction - source host only.
            # It is common situation for different types of backends.
            host = snapshot['share']['host']
            share = self.db.share_update(context, share['id'], {'host': host})
            self.share_rpcapi.create_share(
                context,
                share,
                host,
                request_spec=request_spec,
                filter_properties=filter_properties,
                snapshot_id=snapshot_id,
            )
        else:
            # Shares from scratch and from snapshots when source host is not
            # the only allowed, it is possible, for example, in multibackend
            # installation with Generic drivers only.
            self.scheduler_rpcapi.create_share(
                context,
                CONF.share_topic,
                share['id'],
                snapshot_id,
                request_spec=request_spec,
                filter_properties=filter_properties,
            )

        return share
Exemplo n.º 13
0
    def _create(self, req, body,
                check_create_share_from_snapshot_support=False,
                check_availability_zones_extra_spec=False):
        """Creates a new share."""
        context = req.environ['manila.context']

        if not self.is_valid_body(body, 'share'):
            raise exc.HTTPUnprocessableEntity()

        share = body['share']
        share = common.validate_public_share_policy(context, share)

        # NOTE(rushiagr): Manila API allows 'name' instead of 'display_name'.
        if share.get('name'):
            share['display_name'] = share.get('name')
            del share['name']

        # NOTE(rushiagr): Manila API allows 'description' instead of
        #                 'display_description'.
        if share.get('description'):
            share['display_description'] = share.get('description')
            del share['description']

        size = share['size']
        share_proto = share['share_proto'].upper()

        msg = ("Create %(share_proto)s share of %(size)s GB" %
               {'share_proto': share_proto, 'size': size})
        LOG.info(msg, context=context)

        availability_zone_id = None
        availability_zone = share.get('availability_zone')
        if availability_zone:
            try:
                availability_zone_id = db.availability_zone_get(
                    context, availability_zone).id
            except exception.AvailabilityZoneNotFound as e:
                raise exc.HTTPNotFound(explanation=six.text_type(e))

        share_group_id = share.get('share_group_id')
        if share_group_id:
            try:
                share_group = db.share_group_get(context, share_group_id)
            except exception.ShareGroupNotFound as e:
                raise exc.HTTPNotFound(explanation=six.text_type(e))
            sg_az_id = share_group['availability_zone_id']
            if availability_zone and availability_zone_id != sg_az_id:
                msg = _("Share cannot have AZ ('%(s_az)s') different than "
                        "share group's one (%(sg_az)s).") % {
                            's_az': availability_zone_id, 'sg_az': sg_az_id}
                raise exception.InvalidInput(msg)
            availability_zone_id = sg_az_id

        kwargs = {
            'availability_zone': availability_zone_id,
            'metadata': share.get('metadata'),
            'is_public': share.get('is_public', False),
            'share_group_id': share_group_id,
        }

        snapshot_id = share.get('snapshot_id')
        if snapshot_id:
            snapshot = self.share_api.get_snapshot(context, snapshot_id)
        else:
            snapshot = None

        kwargs['snapshot_id'] = snapshot_id

        share_network_id = share.get('share_network_id')

        parent_share_type = {}
        if snapshot:
            # Need to check that share_network_id from snapshot's
            # parents share equals to share_network_id from args.
            # If share_network_id is empty then update it with
            # share_network_id of parent share.
            parent_share = self.share_api.get(context, snapshot['share_id'])
            parent_share_net_id = parent_share.instance['share_network_id']
            parent_share_type = share_types.get_share_type(
                context, parent_share.instance['share_type_id'])
            if share_network_id:
                if share_network_id != parent_share_net_id:
                    msg = ("Share network ID should be the same as snapshot's"
                           " parent share's or empty")
                    raise exc.HTTPBadRequest(explanation=msg)
            elif parent_share_net_id:
                share_network_id = parent_share_net_id

            # Verify that share can be created from a snapshot
            if (check_create_share_from_snapshot_support and
                    not parent_share['create_share_from_snapshot_support']):
                msg = (_("A new share may not be created from snapshot '%s', "
                         "because the snapshot's parent share does not have "
                         "that capability.")
                       % snapshot_id)
                LOG.error(msg)
                raise exc.HTTPBadRequest(explanation=msg)

        if share_network_id:
            try:
                self.share_api.get_share_network(
                    context,
                    share_network_id)
            except exception.ShareNetworkNotFound as e:
                raise exc.HTTPNotFound(explanation=six.text_type(e))
            kwargs['share_network_id'] = share_network_id

        display_name = share.get('display_name')
        display_description = share.get('display_description')

        if 'share_type' in share and 'volume_type' in share:
            msg = 'Cannot specify both share_type and volume_type'
            raise exc.HTTPBadRequest(explanation=msg)
        req_share_type = share.get('share_type', share.get('volume_type'))

        share_type = None
        if req_share_type:
            try:
                if not uuidutils.is_uuid_like(req_share_type):
                    share_type = share_types.get_share_type_by_name(
                        context, req_share_type)
                else:
                    share_type = share_types.get_share_type(
                        context, req_share_type)
            except exception.ShareTypeNotFound:
                msg = _("Share type not found.")
                raise exc.HTTPNotFound(explanation=msg)
        elif not snapshot:
            def_share_type = share_types.get_default_share_type()
            if def_share_type:
                share_type = def_share_type

        # Only use in create share feature. Create share from snapshot
        # and create share with share group features not
        # need this check.
        if (not share_network_id and not snapshot
                and not share_group_id
                and share_type and share_type.get('extra_specs')
                and (strutils.bool_from_string(share_type.get('extra_specs').
                     get('driver_handles_share_servers')))):
            msg = _('Share network must be set when the '
                    'driver_handles_share_servers is true.')
            raise exc.HTTPBadRequest(explanation=msg)

        type_chosen = share_type or parent_share_type
        if type_chosen and check_availability_zones_extra_spec:
            type_azs = type_chosen.get(
                'extra_specs', {}).get('availability_zones', '')
            type_azs = type_azs.split(',') if type_azs else []
            kwargs['availability_zones'] = type_azs
            if (availability_zone and type_azs and
                    availability_zone not in type_azs):
                msg = _("Share type %(type)s is not supported within the "
                        "availability zone chosen %(az)s.")
                type_chosen = (
                    req_share_type or "%s (from source snapshot)" % (
                        parent_share_type.get('name') or
                        parent_share_type.get('id'))
                )
                payload = {'type': type_chosen, 'az': availability_zone}
                raise exc.HTTPBadRequest(explanation=msg % payload)

        if share_type:
            kwargs['share_type'] = share_type
        new_share = self.share_api.create(context,
                                          share_proto,
                                          size,
                                          display_name,
                                          display_description,
                                          **kwargs)

        return self._view_builder.detail(req, new_share)
Exemplo n.º 14
0
Arquivo: api.py Projeto: jcsp/manila
    def create(self, context, name=None, description=None,
               share_type_ids=None, source_cgsnapshot_id=None,
               share_network_id=None):
        """Create new consistency group."""
        policy.check_policy(context, 'consistency_group', 'create')

        cgsnapshot = None
        original_cg = None
        if source_cgsnapshot_id:
            cgsnapshot = self.db.cgsnapshot_get(context, source_cgsnapshot_id)
            if cgsnapshot['status'] != constants.STATUS_AVAILABLE:
                msg = (_("Consistency group snapshot status must be %s")
                       % constants.STATUS_AVAILABLE)
                raise exception.InvalidCGSnapshot(reason=msg)

            original_cg = self.db.consistency_group_get(context, cgsnapshot[
                'consistency_group_id'])
            share_type_ids = [s['share_type_id'] for s in original_cg[
                'share_types']]

        # Get share_type_objects
        share_type_objects = []
        driver_handles_share_servers = None
        for share_type_id in (share_type_ids or []):
            try:
                share_type_object = share_types.get_share_type(
                    context, share_type_id)
            except exception.ShareTypeNotFound:
                msg = _("Share type with id %s could not be found")
                raise exception.InvalidInput(msg % share_type_id)
            share_type_objects.append(share_type_object)

            extra_specs = share_type_object.get('extra_specs')
            if extra_specs:
                share_type_handle_ss = strutils.bool_from_string(
                    extra_specs.get(
                        constants.ExtraSpecs.DRIVER_HANDLES_SHARE_SERVERS))
                if driver_handles_share_servers is None:
                    driver_handles_share_servers = share_type_handle_ss
                elif not driver_handles_share_servers == share_type_handle_ss:
                    # NOTE(ameade): if the share types have conflicting values
                    #  for driver_handles_share_servers then raise bad request
                    msg = _("The specified share_types cannot have "
                            "conflicting values for the "
                            "driver_handles_share_servers extra spec.")
                    raise exception.InvalidInput(reason=msg)

                if (not share_type_handle_ss) and share_network_id:
                    msg = _("When using a share types with the "
                            "driver_handles_share_servers extra spec as "
                            "False, a share_network_id must not be provided.")
                    raise exception.InvalidInput(reason=msg)

        try:
            if share_network_id:
                self.db.share_network_get(context, share_network_id)
        except exception.ShareNetworkNotFound:
            msg = _("The specified share network does not exist.")
            raise exception.InvalidInput(reason=msg)

        if (driver_handles_share_servers and
                not (source_cgsnapshot_id or share_network_id)):
            msg = _("When using a share type with the "
                    "driver_handles_share_servers extra spec as"
                    "True, a share_network_id must be provided.")
            raise exception.InvalidInput(reason=msg)

        options = {
            'source_cgsnapshot_id': source_cgsnapshot_id,
            'share_network_id': share_network_id,
            'name': name,
            'description': description,
            'user_id': context.user_id,
            'project_id': context.project_id,
            'status': constants.STATUS_CREATING,
            'share_types': share_type_ids
        }
        if original_cg:
            options['host'] = original_cg['host']

        cg = self.db.consistency_group_create(context, options)

        try:
            if cgsnapshot:
                members = self.db.cgsnapshot_members_get_all(
                    context, source_cgsnapshot_id)
                for member in members:
                    share_type = share_types.get_share_type(
                        context, member['share_type_id'])
                    member['share'] = self.db.share_instance_get(
                        context, member['share_instance_id'],
                        with_share_data=True)
                    self.share_api.create(context, member['share_proto'],
                                          member['size'], None, None,
                                          consistency_group_id=cg['id'],
                                          cgsnapshot_member=member,
                                          share_type=share_type,
                                          share_network_id=share_network_id)
        except Exception:
            with excutils.save_and_reraise_exception():
                self.db.consistency_group_destroy(context.elevated(), cg['id'])

        request_spec = {'consistency_group_id': cg['id']}
        request_spec.update(options)
        request_spec['share_types'] = share_type_objects

        if cgsnapshot and original_cg:
            self.share_rpcapi.create_consistency_group(
                context, cg, original_cg['host'])
        else:
            self.scheduler_rpcapi.create_consistency_group(
                context, cg_id=cg['id'], request_spec=request_spec,
                filter_properties={})

        return cg
Exemplo n.º 15
0
 def _check_type(self, context, type_id):
     try:
         share_types.get_share_type(context, type_id)
     except exception.NotFound as ex:
         raise webob.exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 16
0
    def migrate_share(self, context, share, host, force_host_copy):
        """Migrates share to a new host."""

        policy.check_policy(context, 'share', 'migrate')

        share_instance = share.instance

        # We only handle "available" share for now
        if share_instance['status'] != constants.STATUS_AVAILABLE:
            msg = _('Share instance %(instance_id)s status must be available, '
                    'but current status is: %(instance_status)s.') % {
                'instance_id': share_instance['id'],
                'instance_status': share_instance['status']}
            raise exception.InvalidShare(reason=msg)

        self._check_is_share_busy(share)

        # Make sure the destination host is different than the current one
        if host == share_instance['host']:
            msg = _('Destination host %(dest_host)s must be different '
                    'than the current host %(src_host)s.') % {
                'dest_host': host,
                'src_host': share_instance['host']}
            raise exception.InvalidHost(reason=msg)

        # We only handle shares without snapshots for now
        snaps = self.db.share_snapshot_get_all_for_share(context, share['id'])
        if snaps:
            msg = _("Share %s must not have snapshots.") % share['id']
            raise exception.InvalidShare(reason=msg)

        # Make sure the host is in the list of available hosts
        utils.validate_service_host(context, share_utils.extract_host(host))

        # NOTE(ganso): there is the possibility of an error between here and
        # manager code, which will cause the share to be stuck in
        # MIGRATION_STARTING status. According to Liberty Midcycle discussion,
        # this kind of scenario should not be cleaned up, the administrator
        # should be issued to clear this status before a new migration request
        # is made
        self.update(
            context, share,
            {'task_state': constants.STATUS_TASK_STATE_MIGRATION_STARTING})

        share_type = {}
        share_type_id = share['share_type_id']
        if share_type_id:
            share_type = share_types.get_share_type(context, share_type_id)
        request_spec = {'share_properties': share,
                        'share_instance_properties': share_instance.to_dict(),
                        'share_type': share_type,
                        'share_id': share['id']}

        try:
            self.scheduler_rpcapi.migrate_share_to_host(context, share['id'],
                                                        host, force_host_copy,
                                                        request_spec)
        except Exception:
            self.update(
                context, share,
                {'task_state': constants.STATUS_TASK_STATE_MIGRATION_ERROR})
            raise
Exemplo n.º 17
0
    def create(self,
               context,
               name=None,
               description=None,
               share_type_ids=None,
               source_share_group_snapshot_id=None,
               share_network_id=None,
               share_group_type_id=None,
               availability_zone_id=None,
               availability_zone=None):
        """Create new share group."""

        share_group_snapshot = None
        original_share_group = None
        # NOTE(gouthamr): share_server_id is inherited from the
        # parent share group if a share group snapshot is specified,
        # else, it will be set in the share manager.
        share_server_id = None
        if source_share_group_snapshot_id:
            share_group_snapshot = self.db.share_group_snapshot_get(
                context, source_share_group_snapshot_id)
            if share_group_snapshot['status'] != constants.STATUS_AVAILABLE:
                msg = (_("Share group snapshot status must be %s.") %
                       constants.STATUS_AVAILABLE)
                raise exception.InvalidShareGroupSnapshot(reason=msg)

            original_share_group = self.db.share_group_get(
                context, share_group_snapshot['share_group_id'])
            share_type_ids = [
                s['share_type_id'] for s in original_share_group['share_types']
            ]
            share_network_id = original_share_group['share_network_id']
            share_server_id = original_share_group['share_server_id']
            availability_zone_id = original_share_group['availability_zone_id']

        # Get share_type_objects
        share_type_objects = []
        driver_handles_share_servers = None
        for share_type_id in (share_type_ids or []):
            try:
                share_type_object = share_types.get_share_type(
                    context, share_type_id)
            except exception.ShareTypeNotFound:
                msg = _("Share type with id %s could not be found.")
                raise exception.InvalidInput(msg % share_type_id)
            share_type_objects.append(share_type_object)

            extra_specs = share_type_object.get('extra_specs')
            if extra_specs:
                share_type_handle_ss = strutils.bool_from_string(
                    extra_specs.get(
                        constants.ExtraSpecs.DRIVER_HANDLES_SHARE_SERVERS))
                if driver_handles_share_servers is None:
                    driver_handles_share_servers = share_type_handle_ss
                elif not driver_handles_share_servers == share_type_handle_ss:
                    # NOTE(ameade): if the share types have conflicting values
                    #  for driver_handles_share_servers then raise bad request
                    msg = _("The specified share_types cannot have "
                            "conflicting values for the "
                            "driver_handles_share_servers extra spec.")
                    raise exception.InvalidInput(reason=msg)

                if (not share_type_handle_ss) and share_network_id:
                    msg = _("When using a share types with the "
                            "driver_handles_share_servers extra spec as "
                            "False, a share_network_id must not be provided.")
                    raise exception.InvalidInput(reason=msg)

        share_network = {}
        try:
            if share_network_id:
                share_network = self.db.share_network_get(
                    context, share_network_id)
        except exception.ShareNetworkNotFound:
            msg = _("The specified share network does not exist.")
            raise exception.InvalidInput(reason=msg)

        if share_network:
            # Check if share network is active, otherwise raise a BadRequest
            api_common.check_share_network_is_active(share_network)

        if (driver_handles_share_servers
                and not (source_share_group_snapshot_id or share_network_id)):
            msg = _("When using a share type with the "
                    "driver_handles_share_servers extra spec as "
                    "True, a share_network_id must be provided.")
            raise exception.InvalidInput(reason=msg)

        try:
            share_group_type = self.db.share_group_type_get(
                context, share_group_type_id)
        except exception.ShareGroupTypeNotFound:
            msg = _("The specified share group type %s does not exist.")
            raise exception.InvalidInput(reason=msg % share_group_type_id)

        supported_share_types = set(
            [x['share_type_id'] for x in share_group_type['share_types']])
        supported_share_type_objects = [
            share_types.get_share_type(context, share_type_id)
            for share_type_id in supported_share_types
        ]

        if not set(share_type_ids or []) <= supported_share_types:
            msg = _("The specified share types must be a subset of the share "
                    "types supported by the share group type.")
            raise exception.InvalidInput(reason=msg)

        # Grab share type AZs for scheduling
        share_types_of_new_group = (share_type_objects
                                    or supported_share_type_objects)
        stype_azs_of_new_group = []
        stypes_unsupported_in_az = []
        for stype in share_types_of_new_group:
            stype_azs = stype.get('extra_specs',
                                  {}).get('availability_zones', '')
            if stype_azs:
                stype_azs = stype_azs.split(',')
                stype_azs_of_new_group.extend(stype_azs)
                if availability_zone and availability_zone not in stype_azs:
                    # If an AZ is requested, it must be supported by the AZs
                    # configured in each of the share types requested
                    stypes_unsupported_in_az.append(
                        (stype['name'], stype['id']))

        if stypes_unsupported_in_az:
            msg = _("Share group cannot be created since the following share "
                    "types are not supported within the availability zone "
                    "'%(az)s': (%(stypes)s)")
            payload = {'az': availability_zone, 'stypes': ''}
            for type_name, type_id in set(stypes_unsupported_in_az):
                if payload['stypes']:
                    payload['stypes'] += ', '
                type_name = '%s ' % (type_name or '')
            payload['stypes'] += type_name + '(ID: %s)' % type_id
            raise exception.InvalidInput(reason=msg % payload)

        try:
            reservations = QUOTAS.reserve(context, share_groups=1)
        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 'share_groups' in overs:
                msg = ("Quota exceeded for '%(s_uid)s' user in '%(s_pid)s' "
                       "project. (%(d_consumed)d of "
                       "%(d_quota)d already consumed).")
                LOG.warning(
                    msg, {
                        's_pid': context.project_id,
                        's_uid': context.user_id,
                        'd_consumed': _consumed('share_groups'),
                        'd_quota': quotas['share_groups'],
                    })
            raise exception.ShareGroupsLimitExceeded()

        options = {
            'share_group_type_id': share_group_type_id,
            'source_share_group_snapshot_id': source_share_group_snapshot_id,
            'share_network_id': share_network_id,
            'share_server_id': share_server_id,
            'availability_zone_id': availability_zone_id,
            'name': name,
            'description': description,
            'user_id': context.user_id,
            'project_id': context.project_id,
            'status': constants.STATUS_CREATING,
            'share_types': share_type_ids or supported_share_types
        }
        if original_share_group:
            options['host'] = original_share_group['host']

        share_group = {}
        try:
            share_group = self.db.share_group_create(context, options)
            if share_group_snapshot:
                members = self.db.share_group_snapshot_members_get_all(
                    context, source_share_group_snapshot_id)
                for member in members:
                    share_instance = self.db.share_instance_get(
                        context, member['share_instance_id'])
                    share_type = share_types.get_share_type(
                        context, share_instance['share_type_id'])
                    self.share_api.create(
                        context,
                        member['share_proto'],
                        member['size'],
                        None,
                        None,
                        share_group_id=share_group['id'],
                        share_group_snapshot_member=member,
                        share_type=share_type,
                        availability_zone=availability_zone_id,
                        share_network_id=share_network_id)
        except Exception:
            with excutils.save_and_reraise_exception():
                if share_group:
                    self.db.share_group_destroy(context.elevated(),
                                                share_group['id'])
                QUOTAS.rollback(context, reservations)

        try:
            QUOTAS.commit(context, reservations)
        except Exception:
            with excutils.save_and_reraise_exception():
                QUOTAS.rollback(context, reservations)

        request_spec = {'share_group_id': share_group['id']}
        request_spec.update(options)
        request_spec['availability_zones'] = set(stype_azs_of_new_group)
        request_spec['share_types'] = share_type_objects
        request_spec['resource_type'] = share_group_type

        if share_group_snapshot and original_share_group:
            self.share_rpcapi.create_share_group(context, share_group,
                                                 original_share_group['host'])
        else:
            self.scheduler_rpcapi.create_share_group(
                context,
                share_group_id=share_group['id'],
                request_spec=request_spec,
                filter_properties={})

        return share_group