Esempio n. 1
0
    def filter_queryset(self, request, queryset, view):
        event_types = request.query_params.getlist('event_type')
        if event_types:
            queryset = queryset.filter(event_type__in=event_types)

        features = request.query_params.getlist('feature')
        if features:
            queryset = queryset.filter(
                event_type__in=expand_event_groups(features))

        if 'scope' in request.query_params:
            field = core_serializers.GenericRelatedField(
                related_models=utils.get_loggable_models())
            field._context = {'request': request}
            scope = field.to_internal_value(request.query_params['scope'])

            # Check permissions
            visible = scope._meta.model.get_permitted_objects(request.user)
            if not visible.filter(pk=scope.pk).exists():
                return queryset.none()

            content_type = ContentType.objects.get_for_model(scope._meta.model)
            events = models.Feed.objects.filter(
                content_type=content_type,
                object_id=scope.id,
            ).values_list('event_id', flat=True)
            queryset = queryset.filter(id__in=events)

        elif not request.user.is_staff and not request.user.is_support:
            # If user is not staff nor support, he is allowed to see
            # events related to particular scope only.
            queryset = queryset.none()

        return queryset
Esempio n. 2
0
class AlertSerializer(serializers.HyperlinkedModelSerializer):
    scope = GenericRelatedField(related_models=utils.get_loggable_models())
    severity = MappedChoiceField(
        choices=[(v, k) for k, v in models.Alert.SeverityChoices.CHOICES],
        choice_mappings={v: k for k, v in models.Alert.SeverityChoices.CHOICES},
    )
    context = JsonField(read_only=True)

    class Meta(object):
        model = models.Alert
        fields = (
            'url', 'uuid', 'alert_type', 'message', 'severity', 'scope',
            'created', 'closed', 'context', 'acknowledged',
        )
        read_only_fields = ('uuid', 'created', 'closed')
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
        }

    def create(self, validated_data):
        try:
            alert, created = loggers.AlertLogger().process(
                severity=validated_data['severity'],
                message_template=validated_data['message'],
                scope=validated_data['scope'],
                alert_type=validated_data['alert_type'],
            )
        except IntegrityError:
            # In case of simultaneous requests serializer validation can pass for both alerts,
            # so we need to handle DB IntegrityError separately.
            raise serializers.ValidationError(_('Alert with given type and scope already exists.'))
        else:
            return alert
Esempio n. 3
0
 def get_permitted_objects_uuids(self, user):
     from waldur_core.logging.utils import get_loggable_models
     permitted_objects_uuids = {}
     for model in get_loggable_models():
         for field, uuids in model.get_permitted_objects_uuids(
                 user).items():
             permitted_objects_uuids[field] = [uuid.hex for uuid in uuids]
     return permitted_objects_uuids
Esempio n. 4
0
    def setUp(self):
        from waldur_core.structure.tests.factories import UserFactory

        self.user = UserFactory(is_staff=True)
        self.request = APIRequestFactory().get('/')
        self.request.user = self.user

        self.field = GenericRelatedField(related_models=get_loggable_models())
        self.field.root._context = {'request': self.request}
Esempio n. 5
0
    def ready(self):
        from waldur_core.logging import handlers, utils

        for index, model in enumerate(utils.get_loggable_models()):
            signals.post_delete.connect(
                handlers.remove_related_alerts,
                sender=model,
                dispatch_uid=
                'waldur_core.logging.handlers.remove_{}_{}_related_alerts'.
                format(model.__name__, index),
            )
Esempio n. 6
0
    def filtered_for_user(self, user, queryset=None):
        from waldur_core.logging import utils

        if queryset is None:
            queryset = self.get_queryset()
        # XXX: This circular dependency will be removed then filter_queryset_for_user
        # will be moved to model manager method
        from waldur_core.structure.managers import filter_queryset_for_user

        query = Q()
        for model in utils.get_loggable_models():
            user_object_ids = filter_queryset_for_user(
                model.objects.all(), user).values_list('id', flat=True)
            content_type_id = ct_models.ContentType.objects.get_for_model(
                model).id
            query |= Q(object_id__in=user_object_ids,
                       content_type_id=content_type_id)

        return queryset.filter(query)
Esempio n. 7
0
class EventSerializer(serializers.Serializer):
    level = serializers.ChoiceField(
        choices=['debug', 'info', 'warning', 'error'])
    message = serializers.CharField()
    scope = GenericRelatedField(related_models=utils.get_loggable_models(),
                                required=False)
Esempio n. 8
0
    def filter_queryset(self, request, queryset, view):
        search_text = request.query_params.get(
            settings.api_settings.SEARCH_PARAM, '')
        must_terms = {}
        must_not_terms = {}
        should_terms = {}
        excluded_event_types = set()

        if 'event_type' in request.query_params:
            must_terms['event_type'] = request.query_params.getlist(
                'event_type')

        if 'feature' in request.query_params:
            features = request.query_params.getlist('feature')
            must_terms['event_type'] = expand_event_groups(features)

        # Group events by features in order to prevent large HTTP GET request
        if 'exclude_features' in request.query_params:
            features = request.query_params.getlist('exclude_features')
            excluded_event_types.update(expand_event_groups(features))

        if 'exclude_extra' in request.query_params:
            excluded_event_types.update(expand_event_groups(['update']))

        if not django_settings.DEBUG:
            excluded_event_types.update(expand_event_groups(['debug_only']))

        if excluded_event_types:
            must_not_terms['event_type'] = list(excluded_event_types)

        if 'user_username' in request.query_params:
            must_terms['user_username'] = [
                request.query_params.get('user_username')
            ]

        if 'scope' in request.query_params:
            field = core_serializers.GenericRelatedField(
                related_models=utils.get_loggable_models())
            field._context = {'request': request}
            obj = field.to_internal_value(request.query_params['scope'])

            # XXX: Ilja - disabling this hack and re-opening a ticket. Additional analysis is required for
            # a proper resolution
            # # XXX: hack to prevent leaking customer events
            # permitted_uuids = [uuid.hex for uuids in
            #                    obj.get_permitted_objects_uuids(request.user).values() for uuid in uuids]
            # if obj.uuid.hex not in permitted_uuids:
            #     raise ValidationError('You do not have permission to view events for scope %s'
            #                           % request.query_params['scope'])

            for key, val in obj.filter_by_logged_object().items():
                must_terms[format_raw_field(key)] = [val]

        elif 'scope_type' in request.query_params:
            choices = utils.get_scope_types_mapping()
            try:
                scope_type = choices[request.query_params['scope_type']]
            except KeyError:
                raise ValidationError(
                    _('Scope type "%(value)s" is not valid. Has to be one from list: %(items)s.'
                      ) % dict(value=request.query_params['scope_type'],
                               items=', '.join(choices.keys())))
            else:
                permitted_items = scope_type.get_permitted_objects_uuids(
                    request.user).items()
                if not permitted_items:
                    return EmptyQueryset()
                for field, uuids in permitted_items:
                    must_terms[field] = [uuid.hex for uuid in uuids]

        elif 'resource_type' in request.query_params and 'resource_uuid' in request.query_params:
            # Filter events by resource type and uuid.
            # Please note, that permission checks are skipped,
            # because we can't check permission for deleted resources.
            # Also note, that resource type validation is skipped as well,
            # because resource type name formatting is defined in structure application,
            # but we don't want to create circular dependency between logging and structure apps.
            # This issue could be fixed by switching resource type name formatting to str(model._meta)
            # as it is done for scope_type parameter validation.
            must_terms[format_raw_field('resource_type')] = [
                request.query_params['resource_type']
            ]
            must_terms[format_raw_field('resource_uuid')] = [
                request.query_params['resource_uuid']
            ]

        else:
            should_terms.update(
                event_logger.get_permitted_objects_uuids(request.user))

        mapped = {
            'start': request.query_params.get('from'),
            'end': request.query_params.get('to'),
        }
        timestamp_interval_serializer = core_serializers.TimestampIntervalSerializer(
            data={k: v
                  for k, v in mapped.items() if v})
        timestamp_interval_serializer.is_valid(raise_exception=True)
        filter_data = timestamp_interval_serializer.get_filter_data()

        queryset = queryset.filter(search_text=search_text,
                                   should_terms=should_terms,
                                   must_terms=must_terms,
                                   must_not_terms=must_not_terms,
                                   start=filter_data.get('start'),
                                   end=filter_data.get('end'))

        order_by = request.query_params.get('o', '-@timestamp')
        if order_by:
            queryset = queryset.order_by(order_by)

        return queryset
Esempio n. 9
0
    def filter_queryset(self, request, queryset, view):
        mapped = {
            'start': request.query_params.get('from'),
            'end': request.query_params.get('to'),
        }
        timestamp_interval_serializer = core_serializers.TimestampIntervalSerializer(
            data={k: v
                  for k, v in mapped.items() if v})
        timestamp_interval_serializer.is_valid(raise_exception=True)
        filter_data = timestamp_interval_serializer.get_filter_data()
        if 'start' in filter_data:
            queryset = queryset.filter(
                Q(closed__gte=filter_data['start']) | Q(closed__isnull=True))
        if 'end' in filter_data:
            queryset = queryset.filter(created__lte=filter_data['end'])

        if 'opened' in request.query_params:
            queryset = queryset.filter(closed__isnull=True)

        if 'closed' in request.query_params:
            queryset = queryset.filter(closed__isnull=False)

        if 'severity' in request.query_params:
            severity_codes = {
                v: k
                for k, v in models.Alert.SeverityChoices.CHOICES
            }
            severities = [
                severity_codes.get(severity_name)
                for severity_name in request.query_params.getlist('severity')
            ]
            queryset = queryset.filter(severity__in=severities)

        # XXX: this filter is wrong and deprecated, need to be removed after replacement in Portal
        if 'scope_type' in request.query_params:
            choices = {
                camel_case_to_underscore(m.__name__): m
                for m in utils.get_loggable_models()
            }
            try:
                scope_type = choices[request.query_params['scope_type']]
            except KeyError:
                raise ValidationError(
                    _('Scope type "%(value)s" is not valid. Has to be one from list: %(items)s.'
                      ) % dict(value=request.query_params['scope_type'],
                               items=', '.join(choices.keys())))
            else:
                ct = ContentType.objects.get_for_model(scope_type)
                queryset = queryset.filter(content_type=ct)

        if 'alert_type' in request.query_params:
            queryset = queryset.filter(
                alert_type__in=request.query_params.getlist('alert_type'))

        # Group alerts by features in order to prevent large HTTP GET request
        if 'exclude_features' in request.query_params:
            features = request.query_params.getlist('exclude_features')
            queryset = queryset.exclude(
                alert_type__in=expand_alert_groups(features))

        return queryset
Esempio n. 10
0
 def get_related_models(self):
     return utils.get_loggable_models()