Ejemplo n.º 1
0
    def update(self,
               artifact_id,
               type_name=None,
               type_version=None,
               remove_props=None,
               **kwargs):
        """Update attributes of an artifact.

        :param artifact_id: ID of the artifact to modify.
        :param remove_props: List of property names to remove
        :param \*\*kwargs: Artifact attribute names and their new values.
        """
        type_name, type_version = self._check_type_params(
            type_name, type_version)
        url = glare_urls['update_get_delete'].format(version=self.version,
                                                     type_name=type_name,
                                                     type_version=type_version,
                                                     artifact_id=artifact_id)
        hdrs = {'Content-Type': 'application/openstack-images-v2.1-json-patch'}

        artifact_obj = self.get(artifact_id, type_name, type_version)

        changes = []
        if remove_props:
            for prop in remove_props:
                if prop in ArtifactType.generic_properties:
                    msg = "Generic properties cannot be removed"
                    raise exc.HTTPBadRequest(msg)
                if prop not in kwargs:
                    changes.append({'op': 'remove', 'path': '/' + prop})

        for prop in kwargs:
            if prop in artifact_obj.generic_properties:
                op = 'add' if getattr(artifact_obj,
                                      prop) is None else 'replace'
            elif prop in artifact_obj.type_specific_properties:
                if artifact_obj.type_specific_properties[prop] is None:
                    op = 'add'
                else:
                    op = 'replace'
            else:
                msg = ("Property '%s' doesn't exist in type '%s' with version"
                       " '%s'" % (prop, type_name, type_version))
                raise exc.HTTPBadRequest(msg)
            changes.append({
                'op': op,
                'path': '/' + prop,
                'value': kwargs[prop]
            })

        resp, body = self.http_client.patch(url, headers=hdrs, data=changes)
        return ArtifactType(**body)
Ejemplo n.º 2
0
    def _check_type_params(self, type_name, type_version):
        """Check that type name and type versions were specified"""
        type_name = type_name or self.type_name
        type_version = type_version or self.type_version

        if type_name is None:
            msg = "Type name must be specified"
            raise exc.HTTPBadRequest(msg)

        if type_version is None:
            msg = "Type version must be specified"
            raise exc.HTTPBadRequest(msg)

        return type_name, type_version
Ejemplo n.º 3
0
    def image_import(self, image_id, method='glance-direct', uri=None,
                     backend=None, stores=None, allow_failure=True,
                     all_stores=None):
        """Import Image via method."""
        headers = {}
        url = '/v2/images/%s/import' % image_id
        data = {'method': {'name': method}}
        if stores:
            data['stores'] = stores
            if allow_failure:
                data['all_stores_must_succeed'] = False
        if backend is not None:
            headers['x-image-meta-store'] = backend
        if all_stores:
            data['all_stores'] = True
            if allow_failure:
                data['all_stores_must_succeed'] = False

        if uri:
            if method == 'web-download':
                data['method']['uri'] = uri
            else:
                raise exc.HTTPBadRequest('URI is only supported with method: '
                                         '"web-download"')
        resp, body = self.http_client.post(url, data=data, headers=headers)
        return body, resp
Ejemplo n.º 4
0
    def get(self,
            artifact_id,
            type_name=None,
            type_version=None,
            show_level=None):
        """Get information about an artifact.

        :param artifact_id: ID of the artifact to get.
        :param show_level: value of datalization. Possible values:
                           "none", "basic", "direct", "transitive"
        """
        type_name, type_version = self._check_type_params(
            type_name, type_version)

        url = glare_urls['update_get_delete'].format(version=self.version,
                                                     type_name=type_name,
                                                     type_version=type_version,
                                                     artifact_id=artifact_id)
        if show_level:
            if show_level not in ArtifactType.supported_show_levels:
                msg = "Invalid show level: %s" % show_level
                raise exc.HTTPBadRequest(msg)
            url += '?show_level=%s' % show_level
        resp, body = self.http_client.get(url)
        return ArtifactType(**body)
Ejemplo n.º 5
0
    def _validate_sort_param(sort):
        """Validates sorting argument for invalid keys and directions values.

        :param sort: comma-separated list of sort keys with optional <:dir>
        after each key
        """
        for sort_param in sort.strip().split(','):
            key, _sep, dir = sort_param.partition(':')
            if dir and dir not in SORT_DIR_VALUES:
                msg = ('Invalid sort direction: %(sort_dir)s.'
                       ' It must be one of the following: %(available)s.'
                       ) % {'sort_dir': dir,
                            'available': ', '.join(SORT_DIR_VALUES)}
                raise exc.HTTPBadRequest(msg)
            if key not in SORT_KEY_VALUES:
                msg = ('Invalid sort key: %(sort_key)s.'
                       ' It must be one of the following: %(available)s.'
                       ) % {'sort_key': key,
                            'available': ', '.join(SORT_KEY_VALUES)}
                raise exc.HTTPBadRequest(msg)
        return sort
Ejemplo n.º 6
0
 def image_import(self, image_id, method='glance-direct', uri=None):
     """Import Image via method."""
     url = '/v2/images/%s/import' % image_id
     data = {'method': {'name': method}}
     if uri:
         if method == 'web-download':
             data['method']['uri'] = uri
         else:
             raise exc.HTTPBadRequest('URI is only supported with method: '
                                      '"web-download"')
     resp, body = self.http_client.post(url, data=data)
     return body, resp
Ejemplo n.º 7
0
    def __init__(self, **kwargs):
        try:
            for prop in self.generic_properties:
                setattr(self, prop, kwargs.pop(prop))
        except KeyError:
            msg = "Invalid parameters were provided"
            raise exc.HTTPBadRequest(msg)
        self.type_specific_properties = {}
        for key, value in six.iteritems(kwargs):
            try:
                if _is_dependency(value):

                    self.type_specific_properties[key] = ArtifactType(**value)
                elif _is_dependencies_list(value):

                    self.type_specific_properties[key] = [ArtifactType(**elem)
                                                          for elem in value]
                else:
                    self.type_specific_properties[key] = value
            except exc.HTTPBadRequest:
                # if it's not possible to generate artifact object then
                # assign the value as a regular dict.
                self.type_specific_properties[key] = value
Ejemplo n.º 8
0
    def list(self, **kwargs):
        """Retrieve a listing of Image objects.

        :param page_size: Number of images to request in each
                          paginated request.
        :returns: generator over list of Images.
        """

        limit = kwargs.get('limit')
        # NOTE(flaper87): Don't use `get('page_size', DEFAULT_SIZE)` otherwise,
        # it could be possible to send invalid data to the server by passing
        # page_size=None.
        page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE

        def paginate(url, page_size, limit=None):
            next_url = url
            req_id_hdr = {}

            while True:
                if limit and page_size > limit:
                    # NOTE(flaper87): Avoid requesting 2000 images when limit
                    # is 1
                    next_url = next_url.replace("limit=%s" % page_size,
                                                "limit=%s" % limit)

                resp, body = self.http_client.get(next_url, headers=req_id_hdr)
                # NOTE(rsjethani): Store curent request id so that it can be
                # used in subsequent requests. Refer bug #1525259
                req_id_hdr['x-openstack-request-id'] = \
                    utils._extract_request_id(resp)

                for image in body['images']:
                    # NOTE(bcwaldon): remove 'self' for now until we have
                    # an elegant way to pass it into the model constructor
                    # without conflict.
                    image.pop('self', None)
                    # We do not validate the model when listing.
                    # This prevents side-effects of injecting invalid
                    # schema values via v1.
                    yield self.unvalidated_model(**image), resp
                    if limit:
                        limit -= 1
                        if limit <= 0:
                            raise StopIteration

                try:
                    next_url = body['next']
                except KeyError:
                    return

        filters = kwargs.get('filters', {})
        # NOTE(flaper87): We paginate in the client, hence we use
        # the page_size as Glance's limit.
        filters['limit'] = page_size

        tags = filters.pop('tag', [])
        tags_url_params = []

        for tag in tags:
            if not isinstance(tag, six.string_types):
                raise exc.HTTPBadRequest("Invalid tag value %s" % tag)

            tags_url_params.append({'tag': encodeutils.safe_encode(tag)})

        for param, value in filters.items():
            if isinstance(value, six.string_types):
                filters[param] = encodeutils.safe_encode(value)

        url = '/v2/images?%s' % parse.urlencode(filters)

        for param in tags_url_params:
            url = '%s&%s' % (url, parse.urlencode(param))

        if 'sort' in kwargs:
            if 'sort_key' in kwargs or 'sort_dir' in kwargs:
                raise exc.HTTPBadRequest("The 'sort' argument is not supported"
                                         " with 'sort_key' or 'sort_dir'.")
            url = '%s&sort=%s' % (url, self._validate_sort_param(
                kwargs['sort']))
        else:
            sort_dir = self._wrap(kwargs.get('sort_dir', []))
            sort_key = self._wrap(kwargs.get('sort_key', []))

            if len(sort_key) != len(sort_dir) and len(sort_dir) > 1:
                raise exc.HTTPBadRequest(
                    "Unexpected number of sort directions: "
                    "either provide a single sort direction or an equal "
                    "number of sort keys and sort directions.")
            for key in sort_key:
                url = '%s&sort_key=%s' % (url, key)

            for dir in sort_dir:
                url = '%s&sort_dir=%s' % (url, dir)

        if isinstance(kwargs.get('marker'), six.string_types):
            url = '%s&marker=%s' % (url, kwargs['marker'])

        for image, resp in paginate(url, page_size, limit):
            yield image, resp
Ejemplo n.º 9
0
 def _get_image_with_locations_or_fail(self, image_id):
     image = self.get(image_id)
     if getattr(image, 'locations', None) is None:
         raise exc.HTTPBadRequest('The administrator has disabled '
                                  'API access to image locations')
     return image
Ejemplo n.º 10
0
    def list(self, **kwargs):
        """Retrieve a listing of Image objects.

        :param page_size: Number of images to request in each
                          paginated request.
        :returns: generator over list of Images.
        """

        ori_validate_fun = self.model.validate
        empty_fun = lambda *args, **kwargs: None

        limit = kwargs.get('limit')
        # NOTE(flaper87): Don't use `get('page_size', DEFAULT_SIZE)` otherwise,
        # it could be possible to send invalid data to the server by passing
        # page_size=None.
        page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE

        def paginate(url, page_size, limit=None):
            next_url = url

            while True:
                if limit and page_size > limit:
                    # NOTE(flaper87): Avoid requesting 2000 images when limit
                    # is 1
                    next_url = next_url.replace("limit=%s" % page_size,
                                                "limit=%s" % limit)

                resp, body = self.http_client.get(next_url)
                for image in body['images']:
                    # NOTE(bcwaldon): remove 'self' for now until we have
                    # an elegant way to pass it into the model constructor
                    # without conflict.
                    image.pop('self', None)
                    yield self.model(**image)
                    # NOTE(zhiyan): In order to resolve the performance issue
                    # of JSON schema validation for image listing case, we
                    # don't validate each image entry but do it only on first
                    # image entry for each page.
                    self.model.validate = empty_fun

                    if limit:
                        limit -= 1
                        if limit <= 0:
                            raise StopIteration

                # NOTE(zhiyan); Reset validation function.
                self.model.validate = ori_validate_fun

                try:
                    next_url = body['next']
                except KeyError:
                    return

        filters = kwargs.get('filters', {})
        # NOTE(flaper87): We paginate in the client, hence we use
        # the page_size as Glance's limit.
        filters['limit'] = page_size

        tags = filters.pop('tag', [])
        tags_url_params = []

        for tag in tags:
            if isinstance(tag, six.string_types):
                tags_url_params.append({'tag': encodeutils.safe_encode(tag)})

        for param, value in six.iteritems(filters):
            if isinstance(value, six.string_types):
                filters[param] = encodeutils.safe_encode(value)

        url = '/v2/images?%s' % parse.urlencode(filters)

        for param in tags_url_params:
            url = '%s&%s' % (url, parse.urlencode(param))

        if 'sort' in kwargs:
            if 'sort_key' in kwargs or 'sort_dir' in kwargs:
                raise exc.HTTPBadRequest("The 'sort' argument is not supported"
                                         " with 'sort_key' or 'sort_dir'.")
            url = '%s&sort=%s' % (url,
                                  self._validate_sort_param(
                                      kwargs['sort']))
        else:
            sort_dir = self._wrap(kwargs.get('sort_dir', []))
            sort_key = self._wrap(kwargs.get('sort_key', []))

            if len(sort_key) != len(sort_dir) and len(sort_dir) > 1:
                raise exc.HTTPBadRequest(
                    "Unexpected number of sort directions: "
                    "either provide a single sort direction or an equal "
                    "number of sort keys and sort directions.")
            for key in sort_key:
                url = '%s&sort_key=%s' % (url, key)

            for dir in sort_dir:
                url = '%s&sort_dir=%s' % (url, dir)

        for image in paginate(url, page_size, limit):
            yield image
Ejemplo n.º 11
0
    def list(self, **kwargs):
        """Retrieve a listing of Image objects.

        :param page_size: Number of images to request in each
                          paginated request.
        :returns: generator over list of Images.
        """

        limit = kwargs.get('limit')
        # NOTE(flaper87): Don't use `get('page_size', DEFAULT_SIZE)` otherwise,
        # it could be possible to send invalid data to the server by passing
        # page_size=None.
        page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE

        def paginate(url, page_size, limit=None):
            next_url = url

            while True:
                if limit and page_size > limit:
                    # NOTE(flaper87): Avoid requesting 2000 images when limit
                    # is 1
                    next_url = next_url.replace("limit=%s" % page_size,
                                                "limit=%s" % limit)

                resp, body = self.http_client.get(next_url)
                for image in body['images']:
                    # NOTE(bcwaldon): remove 'self' for now until we have
                    # an elegant way to pass it into the model constructor
                    # without conflict.
                    image.pop('self', None)
                    # We do not validate the model when listing.
                    # This prevents side-effects of injecting invalid
                    # schema values via v1.
                    yield self.unvalidated_model(**image)
                    if limit:
                        limit -= 1
                        if limit <= 0:
                            raise StopIteration

                try:
                    next_url = body['next']
                except KeyError:
                    return

        filters = kwargs.get('filters', {})
        # NOTE(flaper87): We paginate in the client, hence we use
        # the page_size as Glance's limit.
        filters['limit'] = page_size

        tags = filters.pop('tag', [])
        tags_url_params = []

        for tag in tags:
            if not isinstance(tag, six.string_types):
                raise exc.HTTPBadRequest("Invalid tag value %s" % tag)

            tags_url_params.append({'tag': encodeutils.safe_encode(tag)})

        for param, value in six.iteritems(filters):
            if isinstance(value, six.string_types):
                filters[param] = encodeutils.safe_encode(value)

        url = '/v2/images?%s' % parse.urlencode(filters)

        for param in tags_url_params:
            url = '%s&%s' % (url, parse.urlencode(param))

        if isinstance(kwargs.get('marker'), six.string_types):
            url = '%s&marker=%s' % (url, kwargs['marker'])

        for image in paginate(url, page_size, limit):
            yield image