Exemple #1
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
Exemple #2
0
class HostSerializer(structure_serializers.BaseResourceSerializer):
    service = serializers.HyperlinkedRelatedField(
        source='service_project_link.service',
        view_name='zabbix-detail',
        read_only=True,
        lookup_field='uuid')

    service_project_link = serializers.HyperlinkedRelatedField(
        view_name='zabbix-spl-detail',
        queryset=models.ZabbixServiceProjectLink.objects.all(),
        allow_null=True,
        required=False,
    )

    # visible name could be populated from scope, so we need to mark it as not required
    visible_name = serializers.CharField(
        required=False, max_length=models.Host.VISIBLE_NAME_MAX_LENGTH)
    scope = GenericRelatedField(
        related_models=structure_models.ResourceMixin.get_all_models(),
        required=False)
    templates = NestedTemplateSerializer(
        queryset=models.Template.objects.all().prefetch_related(
            'items', 'children'),
        many=True,
        required=False)
    status = MappedChoiceField(
        choices={v: v
                 for _, v in models.Host.Statuses.CHOICES},
        choice_mappings={v: k
                         for k, v in models.Host.Statuses.CHOICES},
        read_only=True,
    )
    interface_ip = serializers.IPAddressField(
        allow_blank=True,
        required=False,
        write_only=True,
        help_text='IP of host interface.')
    interface_parameters = serializers.JSONField(read_only=True)

    class Meta(structure_serializers.BaseResourceSerializer.Meta):
        model = models.Host
        view_name = 'zabbix-host-detail'
        fields = structure_serializers.BaseResourceSerializer.Meta.fields + (
            'visible_name',
            'host_group_name',
            'scope',
            'templates',
            'error',
            'status',
            'interface_ip',
            'interface_parameters',
        )
        read_only_fields = structure_serializers.BaseResourceSerializer.Meta.read_only_fields + (
            'error', 'interface_parameters')
        protected_fields = structure_serializers.BaseResourceSerializer.Meta.protected_fields + (
            'interface_ip', 'visible_name')

    def get_resource_fields(self):
        return super(HostSerializer, self).get_resource_fields() + ['scope']

    def validate(self, attrs):
        attrs = super(HostSerializer, self).validate(attrs)

        # model validation
        if self.instance is not None:
            for name, value in attrs.items():
                setattr(self.instance, name, value)
            self.instance.clean()
        else:
            service_settings = attrs.get(
                'service_project_link').service.settings
            if service_settings.state == structure_models.ServiceSettings.States.ERRED:
                raise serializers.ValidationError(
                    'It is impossible to create host if service is in ERRED state.'
                )

            if not attrs.get('visible_name'):
                if 'scope' not in attrs:
                    raise serializers.ValidationError(
                        'Visible name or scope should be defined.')

                # initiate name and visible name from scope if it is defined
                attrs[
                    'visible_name'] = models.Host.get_visible_name_from_scope(
                        attrs['scope'])

            spl = attrs['service_project_link']
            if models.Host.objects.filter(
                    service_project_link__service__settings=spl.service.
                    settings,
                    visible_name=attrs['visible_name']).exists():
                raise serializers.ValidationError(
                    {'visible_name': 'Visible name should be unique.'})

            instance = models.Host(
                **{
                    k: v
                    for k, v in attrs.items()
                    if k not in ('templates', 'interface_ip')
                })
            instance.clean()

        spl = attrs.get(
            'service_project_link') or self.instance.service_project_link
        templates = attrs.get('templates', [])
        parents = {}  # dictionary <parent template: child template>
        for template in templates:
            if template.settings != spl.service.settings:
                raise serializers.ValidationError({
                    'templates':
                    'Template "%s" and host belong to different service settings.'
                    % template.name
                })
            for child in template.children.all():
                if child in templates:
                    message = 'Template "%s" is already registered as child of template "%s"' % (
                        child.name, template.name)
                    raise serializers.ValidationError({'templates': message})
            for parent in template.parents.all():
                if parent in parents:
                    message = 'Templates %s and %s belong to the same parent %s' % (
                        template, parents[parent], parent)
                    raise serializers.ValidationError({'templates': message})
                else:
                    parents[parent] = template

        for template in templates:
            if template in parents:
                message = 'Template "%s" is already registered as a parent of template "%s"' % \
                          (template, parents[template])
                raise serializers.ValidationError({'templates': message})

        return attrs

    def create(self, validated_data):
        # define interface parameters based on settings and user input
        spl = validated_data['service_project_link']
        interface_parameters = spl.service.settings.get_option(
            'interface_parameters')
        scope = validated_data.get('scope')
        interface_ip = validated_data.pop('interface_ip', None) or getattr(
            scope, 'internal_ips', None)
        if interface_ip:
            # Note, that we're not supporting multiple network interfaces for single host yet.
            # IPv6 is not supported yet too.
            if isinstance(interface_ip, list):
                interface_ip = interface_ip[0]
            interface_parameters['ip'] = interface_ip
        validated_data['interface_parameters'] = interface_parameters

        # populate templates
        templates = validated_data.pop('templates', None)
        with transaction.atomic():
            host = super(HostSerializer, self).create(validated_data)
            # get default templates from service settings if they are not defined
            if templates is None:
                templates = models.Template.objects.filter(
                    settings=host.service_project_link.service.settings,
                    name__in=host.service_project_link.service.settings.
                    get_option('templates_names'),
                )
            for template in templates:
                host.templates.add(template)

        return host

    def update(self, host, validated_data):
        templates = validated_data.pop('templates', None)
        with transaction.atomic():
            host = super(HostSerializer, self).update(host, validated_data)
            if templates is not None:
                host.templates.clear()
                for template in templates:
                    host.templates.add(template)

        return host
Exemple #3
0
class UserSerializer(structure_serializers.BasePropertySerializer):
    groups = NestedUserGroupSerializer(queryset=models.UserGroup.objects.all(),
                                       many=True)
    state = MappedChoiceField(
        choices={v: v
                 for _, v in models.User.States.CHOICES},
        choice_mappings={v: k
                         for k, v in models.User.States.CHOICES},
        read_only=True,
    )
    type = MappedChoiceField(
        choices={v: v
                 for _, v in models.User.Types.CHOICES},
        choice_mappings={v: k
                         for k, v in models.User.Types.CHOICES},
    )
    password = serializers.SerializerMethodField(
        help_text=
        'Password is visible only after user creation or if user has type "default".'
    )

    class Meta:
        model = models.User
        fields = ('url', 'alias', 'name', 'surname', 'type', 'groups',
                  'backend_id', 'settings', 'state', 'phone', 'password')
        read_only_fields = (
            'url',
            'backend_id',
        )
        protected_fields = ('settings', )
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'zabbix-user-detail'
            },
            'settings': {
                'lookup_field': 'uuid'
            },
        }

    def get_password(self, user):
        show_password = ((self.context['request'].method == 'POST'
                          and user is None)
                         or user.type == models.User.Types.DEFAULT)
        return user.password if show_password else None

    def get_fields(self):
        fields = super(UserSerializer, self).get_fields()
        fields[
            'settings'].queryset = structure_models.ServiceSettings.objects.filter(
                type=apps.ZabbixConfig.service_name)
        return fields

    def validate_type(self, value):
        user = self.context['request'].user
        if not user.is_staff and value != models.User.Types.DEFAULT:
            raise serializers.ValidationError(
                'Cannot create not default user.')
        return value

    def validate(self, attrs):
        settings = attrs.get('settings') or self.instance.settings
        groups = attrs.get('groups', [])
        if any([group.settings != settings for group in groups]):
            raise serializers.ValidationError(
                'User groups and user should belong to the same service settings'
            )
        return attrs

    def create(self, attrs):
        groups = attrs.pop('groups', [])
        attrs['password'] = pwgen()
        user = super(UserSerializer, self).create(attrs)
        user.groups.add(*groups)
        return user

    def update(self, user, attrs):
        new_groups = set(attrs.pop('groups', []))
        old_groups = set(user.groups.all())
        user = super(UserSerializer, self).update(user, attrs)
        user.groups.remove(*(old_groups - new_groups))
        user.groups.add(*(new_groups - old_groups))
        return user
Exemple #4
0
class ITServiceSerializer(structure_serializers.BaseResourceSerializer):
    service = serializers.HyperlinkedRelatedField(
        source='service_project_link.service',
        view_name='zabbix-detail',
        read_only=True,
        lookup_field='uuid')

    service_project_link = serializers.HyperlinkedRelatedField(
        view_name='zabbix-spl-detail',
        queryset=models.ZabbixServiceProjectLink.objects.all(),
        allow_null=True,
        required=False,
    )

    host = serializers.HyperlinkedRelatedField(
        view_name='zabbix-host-detail',
        queryset=models.Host.objects.all(),
        lookup_field='uuid')

    trigger = serializers.HyperlinkedRelatedField(
        view_name='zabbix-trigger-detail',
        queryset=models.Trigger.objects.order_by('name').select_related(
            'settings'),
        lookup_field='uuid')

    algorithm = MappedChoiceField(
        choices={v: v
                 for _, v in models.ITService.Algorithm.CHOICES},
        choice_mappings={v: k
                         for k, v in models.ITService.Algorithm.CHOICES},
    )
    trigger_name = serializers.ReadOnlyField(source='trigger.name')
    actual_sla = serializers.SerializerMethodField()

    class Meta(structure_serializers.BaseResourceSerializer.Meta):
        model = models.ITService
        view_name = 'zabbix-itservice-detail'
        fields = structure_serializers.BaseResourceSerializer.Meta.fields + (
            'host', 'algorithm', 'sort_order', 'agreed_sla', 'actual_sla',
            'trigger', 'trigger_name', 'is_main')

    # XXX: Should we display sla here?
    def get_actual_sla(self, itservice):
        key = 'itservice_sla_map'
        if key not in self.context:
            qs = models.SlaHistory.objects.filter(
                period=get_period(self.context['request']))
            if isinstance(self.instance, list):
                qs = qs.filter(itservice__in=self.instance)
            else:
                qs = qs.filter(itservice=self.instance)
            self.context[key] = {q.itservice_id: q.value for q in qs}

        return self.context[key].get(itservice.id)

    def validate(self, attrs):
        attrs = super(ITServiceSerializer, self).validate(attrs)

        host = attrs.get('host')
        if host:
            trigger = attrs['trigger']

            if host and not host.templates.filter(
                    id=trigger.template_id).exists():
                raise serializers.ValidationError(
                    "Host templates should contain trigger's template")

            if host.service_project_link != attrs['service_project_link']:
                raise serializers.ValidationError(
                    'Host and IT service should belong to the same SPL.')

        return attrs
Exemple #5
0
class ServiceSettingsSerializer(
    PermissionFieldFilteringMixin,
    core_serializers.RestrictedSerializerMixin,
    core_serializers.AugmentedSerializerMixin,
    serializers.HyperlinkedModelSerializer,
):
    customer_native_name = serializers.ReadOnlyField(source='customer.native_name')
    state = MappedChoiceField(
        choices=[(v, k) for k, v in core_models.StateMixin.States.CHOICES],
        choice_mappings={v: k for k, v in core_models.StateMixin.States.CHOICES},
        read_only=True,
    )
    scope = core_serializers.GenericRelatedField(
        related_models=models.BaseResource.get_all_models(),
        required=False,
        allow_null=True,
    )
    options = serializers.DictField()

    class Meta:
        model = models.ServiceSettings
        fields = (
            'url',
            'uuid',
            'name',
            'type',
            'state',
            'error_message',
            'shared',
            'customer',
            'customer_name',
            'customer_native_name',
            'terms_of_services',
            'scope',
            'options',
        )
        protected_fields = ('type', 'customer')
        read_only_fields = ('shared', 'state', 'error_message')
        related_paths = ('customer',)
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
            'customer': {'lookup_field': 'uuid'},
        }

    def get_filtered_field_names(self):
        return ('customer',)

    @staticmethod
    def eager_load(queryset, request=None):
        return queryset.select_related('customer')

    def get_fields(self):
        fields = super(ServiceSettingsSerializer, self).get_fields()
        method = self.context['view'].request.method
        if method == 'GET' and 'options' in fields:
            fields['options'] = serializers.SerializerMethodField('get_options')
        return fields

    def get_options(self, service):
        options = {
            'backend_url': service.backend_url,
            'username': service.username,
            'password': service.password,
            'domain': service.domain,
            'token': service.token,
            **service.options,
        }
        request = self.context['request']

        if request.user.is_staff:
            return options

        if service.customer and service.customer.has_user(
            request.user, models.CustomerRole.OWNER
        ):
            return options

        options_serializer_class = get_options_serializer_class(service.type)
        secret_fields = options_serializer_class.Meta.secret_fields
        return {k: v for (k, v) in options.items() if k not in secret_fields}

    def validate(self, attrs):
        if 'options' not in attrs:
            return attrs
        service_type = self.instance and self.instance.type or attrs['type']
        options_serializer_class = get_options_serializer_class(service_type)
        options_serializer = options_serializer_class(
            instance=self.instance, data=attrs['options'], context=self.context
        )
        options_serializer.is_valid(raise_exception=True)
        service_options = options_serializer.validated_data
        attrs.update(service_options)
        self._validate_settings(models.ServiceSettings(**attrs))
        return attrs

    def _validate_settings(self, service_settings):
        try:
            backend = service_settings.get_backend()
            backend.validate_settings()
        except ServiceBackendError as e:
            raise serializers.ValidationError(_('Wrong settings: %s.') % e)
        except ServiceBackendNotImplemented:
            pass