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
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
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
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()
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()]
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
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