def _filter_images(images, filters, context):
    filtered_images = []
    if 'properties' in filters:
        prop_filter = filters.pop('properties')
        filters.update(prop_filter)

    is_public_filter = filters.pop('is_public', None)

    for i, image in enumerate(images):
        add = True
        for k, value in filters.iteritems():
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    value = int(value)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)
            if k.endswith('_min'):
                add = image.get(key) >= value
            elif k.endswith('_max'):
                add = image.get(key) <= value
            elif image.get(k) is not None:
                add = image.get(key) == value
            else:
                properties = {}
                for p in image['properties']:
                    properties = {
                        p['name']: p['value'],
                        'deleted': p['deleted']
                    }
                add = (properties.get(key) == value
                       and properties.get('deleted') is False)
            if not add:
                break

        if add:
            filtered_images.append(image)

    #NOTE(bcwaldon): This hacky code is only here to match what the
    # sqlalchemy driver wants - refactor it out of the db layer when
    # it seems appropriate
    if is_public_filter is not None:

        def _filter_ownership(image):
            has_ownership = image['owner'] == context.owner
            can_see = image['is_public'] or has_ownership or context.is_admin

            if can_see:
                return (has_ownership or
                        (can_see and image['is_public'] == is_public_filter))
            else:
                return False

        filtered_images = filter(_filter_ownership, filtered_images)

    return filtered_images
Exemple #2
0
def _filter_images(images, filters):
    filtered_images = []
    if 'properties' in filters:
        prop_filter = filters.pop('properties')
        filters.update(prop_filter)

    for i, image in enumerate(images):
        add = True
        for k, value in filters.iteritems():
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    value = int(value)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)
            if k.endswith('_min'):
                add = image.get(key) >= value
            elif k.endswith('_max'):
                add = image.get(key) <= value
            elif image.get(k) is not None:
                add = image.get(key) == value
            else:
                properties = {}
                for p in image['properties']:
                    properties = {
                        p['name']: p['value'],
                        'deleted': p['deleted']
                    }
                add = properties.get(key) == value and \
                                             properties.get('deleted') is False
            if not add:
                break

        if add:
            filtered_images.append(image)
    return filtered_images
Exemple #3
0
def _filter_images(images, filters, context, status='accepted'):
    filtered_images = []
    if 'properties' in filters:
        prop_filter = filters.pop('properties')
        filters.update(prop_filter)

    if 'is_public' in filters and filters['is_public'] is None:
        filters.pop('is_public')

    if status == 'all':
        status = None

    visibility = filters.pop('visibility', None)

    for image in images:
        member = image_member_find(context,
                                   image_id=image['id'],
                                   member=context.owner,
                                   status=status)
        is_member = len(member) > 0
        has_ownership = context.owner and image['owner'] == context.owner
        can_see = (image['is_public'] or has_ownership or context.is_admin
                   or is_member)
        if not can_see:
            continue

        if visibility:
            if visibility == 'public':
                filters['is_public'] = True
                if not image['is_public']:
                    continue
            elif visibility == 'private':
                filters['is_public'] = False
                if not (has_ownership or context.is_admin):
                    continue
            elif visibility == 'shared':
                if not is_member:
                    continue
        add = True
        for k, value in filters.iteritems():
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    value = int(value)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)
            if k.endswith('_min'):
                add = image.get(key) >= value
            elif k.endswith('_max'):
                add = image.get(key) <= value
            elif image.get(k) is not None:
                add = image.get(key) == value
            else:
                properties = {}
                for p in image['properties']:
                    properties = {
                        p['name']: p['value'],
                        'deleted': p['deleted']
                    }
                add = (properties.get(key) == value
                       and properties.get('deleted') is False)
            if not add:
                break

        if add:
            filtered_images.append(image)

    return filtered_images
Exemple #4
0
def image_get_all(context,
                  filters=None,
                  marker=None,
                  limit=None,
                  sort_key='created_at',
                  sort_dir='desc'):
    """
    Get all images that match zero or more filters.

    :param filters: dict of filter keys and values. If a 'properties'
                    key is present, it is treated as a dict of key/value
                    filters on the image properties attribute
    :param marker: image id after which to start page
    :param limit: maximum number of images to return
    :param sort_key: image attribute by which results should be sorted
    :param sort_dir: direction in which results should be sorted (asc, desc)
    """
    filters = filters or {}

    session = get_session()
    query = session.query(models.Image)\
                   .options(sa_orm.joinedload(models.Image.properties))

    if 'is_public' in filters and filters['is_public'] is not None:
        the_filter = [models.Image.is_public == filters['is_public']]
        if filters['is_public'] and context.owner is not None:
            the_filter.extend([(models.Image.owner == context.owner),
                               models.Image.members.any(member=context.owner,
                                                        deleted=False)])
        if len(the_filter) > 1:
            query = query.filter(sa_sql.or_(*the_filter))
        else:
            query = query.filter(the_filter[0])
        del filters['is_public']

    showing_deleted = False
    if 'changes-since' in filters:
        # normalize timestamp to UTC, as sqlalchemy doesn't appear to
        # respect timezone offsets
        changes_since = timeutils.normalize_time(filters.pop('changes-since'))
        query = query.filter(models.Image.updated_at > changes_since)
        showing_deleted = True

    if 'deleted' in filters:
        deleted_filter = filters.pop('deleted')
        query = query.filter_by(deleted=deleted_filter)
        showing_deleted = deleted_filter
        # TODO(bcwaldon): handle this logic in registry server
        if not deleted_filter:
            query = query.filter(models.Image.status != 'killed')

    for (k, v) in filters.pop('properties', {}).items():
        query = query.filter(
            models.Image.properties.any(name=k, value=v, deleted=False))

    for (k, v) in filters.items():
        if v is not None:
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    v = int(v)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)

            if k.endswith('_min'):
                query = query.filter(getattr(models.Image, key) >= v)
            elif k.endswith('_max'):
                query = query.filter(getattr(models.Image, key) <= v)
            elif hasattr(models.Image, key):
                query = query.filter(getattr(models.Image, key) == v)
            else:
                query = query.filter(
                    models.Image.properties.any(name=key, value=v))

    marker_image = None
    if marker is not None:
        marker_image = image_get(context,
                                 marker,
                                 force_show_deleted=showing_deleted)

    query = paginate_query(query,
                           models.Image,
                           limit, [sort_key, 'created_at', 'id'],
                           marker=marker_image,
                           sort_dir=sort_dir)

    return query.all()
Exemple #5
0
def image_get_all(context, filters=None, marker=None, limit=None,
                  sort_key='created_at', sort_dir='desc',
                  member_status='accepted', is_public=None):
    """
    Get all images that match zero or more filters.

    :param filters: dict of filter keys and values. If a 'properties'
                    key is present, it is treated as a dict of key/value
                    filters on the image properties attribute
    :param marker: image id after which to start page
    :param limit: maximum number of images to return
    :param sort_key: image attribute by which results should be sorted
    :param sort_dir: direction in which results should be sorted (asc, desc)
    :param member_status: only return shared images that have this membership
                          status
    :param is_public: If true, return only public images. If false, return
                      only private and shared images.
    """
    filters = filters or {}

    session = _get_session()
    query = session.query(models.Image)\
                   .options(sa_orm.joinedload(models.Image.properties))\
                   .options(sa_orm.joinedload(models.Image.locations))

    if not context.is_admin:
        visibility_filters = [models.Image.is_public == True]

        if context.owner is not None:
            if member_status == 'all':
                visibility_filters.extend([
                    models.Image.owner == context.owner,
                    models.Image.members.any(member=context.owner,
                                             deleted=False),
                ])
            else:
                visibility_filters.extend([
                    models.Image.owner == context.owner,
                    models.Image.members.any(member=context.owner,
                                             deleted=False,
                                             status=member_status),
                ])

        query = query.filter(sa_sql.or_(*visibility_filters))

    if 'visibility' in filters:
        visibility = filters.pop('visibility')
        if visibility == 'public':
            query = query.filter(models.Image.is_public == True)
        elif visibility == 'private':
            query = query.filter(models.Image.is_public == False)
            if (not context.is_admin) and context.owner is not None:
                query = query.filter(
                    models.Image.owner == context.owner)
        else:
            query = query.filter(
                models.Image.members.any(member=context.owner,
                                         deleted=False))

    if is_public is not None:
        query = query.filter(models.Image.is_public == is_public)

    if 'is_public' in filters:
        spec = models.Image.properties.any(name='is_public',
                                           value=filters.pop('is_public'),
                                           deleted=False)
        query = query.filter(spec)

    showing_deleted = False
    if 'changes-since' in filters:
        # normalize timestamp to UTC, as sqlalchemy doesn't appear to
        # respect timezone offsets
        changes_since = timeutils.normalize_time(filters.pop('changes-since'))
        query = query.filter(models.Image.updated_at > changes_since)
        showing_deleted = True

    if 'deleted' in filters:
        deleted_filter = filters.pop('deleted')
        query = query.filter_by(deleted=deleted_filter)
        showing_deleted = deleted_filter
        # TODO(bcwaldon): handle this logic in registry server
        if not deleted_filter:
            query = query.filter(models.Image.status != 'killed')

    for (k, v) in filters.pop('properties', {}).items():
        query = query.filter(models.Image.properties.any(name=k,
                                                         value=v,
                                                         deleted=False))

    for (k, v) in filters.items():
        if v is not None:
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    v = int(v)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)

            if k.endswith('_min'):
                query = query.filter(getattr(models.Image, key) >= v)
            elif k.endswith('_max'):
                query = query.filter(getattr(models.Image, key) <= v)
            elif hasattr(models.Image, key):
                query = query.filter(getattr(models.Image, key) == v)
            else:
                query = query.filter(models.Image.properties.any(name=key,
                                                                 value=v))

    marker_image = None
    if marker is not None:
        marker_image = _image_get(context, marker,
                                  force_show_deleted=showing_deleted)

    query = _paginate_query(query, models.Image, limit,
                            [sort_key, 'created_at', 'id'],
                            marker=marker_image,
                            sort_dir=sort_dir)

    return [_normalize_locations(image.to_dict()) for image in query.all()]
Exemple #6
0
def _filter_images(images,
                   filters,
                   context,
                   status='accepted',
                   is_public=None,
                   admin_as_user=False):
    filtered_images = []
    if 'properties' in filters:
        prop_filter = filters.pop('properties')
        filters.update(prop_filter)

    if status == 'all':
        status = None

    visibility = filters.pop('visibility', None)

    for image in images:
        member = image_member_find(context,
                                   image_id=image['id'],
                                   member=context.owner,
                                   status=status)
        is_member = len(member) > 0
        has_ownership = context.owner and image['owner'] == context.owner
        can_see = (image['is_public'] or has_ownership or is_member
                   or (context.is_admin and not admin_as_user))
        if not can_see:
            continue

        if visibility:
            if visibility == 'public':
                if not image['is_public']:
                    continue
            elif visibility == 'private':
                if image['is_public']:
                    continue
                if not (has_ownership or
                        (context.is_admin and not admin_as_user)):
                    continue
            elif visibility == 'shared':
                if not is_member:
                    continue

        if is_public is not None:
            if not image['is_public'] == is_public:
                continue

        to_add = True
        for k, value in six.iteritems(filters):
            key = k
            if k.endswith('_min') or k.endswith('_max'):
                key = key[0:-4]
                try:
                    value = int(value)
                except ValueError:
                    msg = _("Unable to filter on a range "
                            "with a non-numeric value.")
                    raise exception.InvalidFilterRangeValue(msg)
            if k.endswith('_min'):
                to_add = image.get(key) >= value
            elif k.endswith('_max'):
                to_add = image.get(key) <= value
            elif k != 'is_public' and image.get(k) is not None:
                to_add = image.get(key) == value
            elif k == 'tags':
                filter_tags = value
                image_tags = image_tag_get_all(context, image['id'])
                for tag in filter_tags:
                    if tag not in image_tags:
                        to_add = False
                        break
            else:
                to_add = False
                for p in image['properties']:
                    properties = {
                        p['name']: p['value'],
                        'deleted': p['deleted']
                    }
                    to_add |= (properties.get(key) == value
                               and properties.get('deleted') is False)

            if not to_add:
                break

        if to_add:
            filtered_images.append(image)

    return filtered_images
Exemple #7
0
def _make_conditions_from_filters(filters, is_public=None):
    #NOTE(venkatesh) make copy of the filters are to be altered in this method.
    filters = filters.copy()

    image_conditions = []
    prop_conditions = []
    tag_conditions = []

    if is_public is not None:
        image_conditions.append(models.Image.is_public == is_public)

    if 'checksum' in filters:
        checksum = filters.pop('checksum')
        image_conditions.append(models.Image.checksum == checksum)

    if 'is_public' in filters:
        key = 'is_public'
        value = filters.pop('is_public')
        prop_filters = _make_image_property_condition(key=key, value=value)
        prop_conditions.append(prop_filters)

    for (k, v) in filters.pop('properties', {}).items():
        prop_filters = _make_image_property_condition(key=k, value=v)
        prop_conditions.append(prop_filters)

    if 'changes-since' in filters:
        # normalize timestamp to UTC, as sqlalchemy doesn't appear to
        # respect timezone offsets
        changes_since = timeutils.normalize_time(filters.pop('changes-since'))
        image_conditions.append(models.Image.updated_at > changes_since)

    if 'deleted' in filters:
        deleted_filter = filters.pop('deleted')
        image_conditions.append(models.Image.deleted == deleted_filter)
        # TODO(bcwaldon): handle this logic in registry server
        if not deleted_filter:
            image_statuses = [s for s in STATUSES if s != 'killed']
            image_conditions.append(models.Image.status.in_(image_statuses))

    if 'tags' in filters:
        tags = filters.pop('tags')
        for tag in tags:
            tag_filters = [models.ImageTag.deleted == False]
            tag_filters.extend([models.ImageTag.value == tag])
            tag_conditions.append(tag_filters)

    filters = dict([(k, v) for k, v in filters.items() if v is not None])

    for (k, v) in filters.items():
        key = k
        if k.endswith('_min') or k.endswith('_max'):
            key = key[0:-4]
            try:
                v = int(filters.pop(k))
            except ValueError:
                msg = _("Unable to filter on a range "
                        "with a non-numeric value.")
                raise exception.InvalidFilterRangeValue(msg)

            if k.endswith('_min'):
                image_conditions.append(getattr(models.Image, key) >= v)
            if k.endswith('_max'):
                image_conditions.append(getattr(models.Image, key) <= v)

    for (k, v) in filters.items():
        value = filters.pop(k)
        if hasattr(models.Image, k):
            image_conditions.append(getattr(models.Image, k) == value)
        else:
            prop_filters = _make_image_property_condition(key=k, value=value)
            prop_conditions.append(prop_filters)

    return image_conditions, prop_conditions, tag_conditions