예제 #1
0
    def setUp(self):
        from nodeconductor.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}
예제 #2
0
class GenericRelatedFieldTest(APITransactionTestCase):
    def setUp(self):
        from nodeconductor.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}

    def test_if_related_object_exists_it_is_deserialized(self):
        from nodeconductor.structure.tests.factories import CustomerFactory
        customer = CustomerFactory()
        valid_url = CustomerFactory.get_url(customer)
        self.assertEqual(self.field.to_internal_value(valid_url), customer)

    def test_if_related_object_does_not_exist_validation_error_is_raised(self):
        from nodeconductor.structure.tests.factories import CustomerFactory
        customer = CustomerFactory()
        valid_url = CustomerFactory.get_url(customer)
        customer.delete()
        self.assertRaises(serializers.ValidationError, self.field.to_internal_value, valid_url)

    def test_if_user_does_not_have_permissions_for_related_object_validation_error_is_raised(self):
        from nodeconductor.structure.tests.factories import CustomerFactory
        customer = CustomerFactory()
        valid_url = CustomerFactory.get_url(customer)
        self.user.is_staff = False
        self.user.save()
        self.assertRaises(serializers.ValidationError, self.field.to_internal_value, valid_url)

    def test_if_uuid_is_invalid_validation_error_is_raised(self):
        invalid_url = 'https://example.com/api/customers/invalid/'
        self.assertRaises(serializers.ValidationError, self.field.to_internal_value, invalid_url)
예제 #3
0
class PriceListItemSerializer(AugmentedSerializerMixin,
                              serializers.HyperlinkedModelSerializer):
    service = GenericRelatedField(
        related_models=structure_models.Service.get_all_models())
    default_price_list_item = serializers.HyperlinkedRelatedField(
        view_name='defaultpricelistitem-detail',
        lookup_field='uuid',
        queryset=models.DefaultPriceListItem.objects.all().select_related(
            'resource_content_type'))

    class Meta:
        model = models.PriceListItem
        fields = ('url', 'uuid', 'units', 'value', 'service',
                  'default_price_list_item')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid'
            },
            'default_price_list_item': {
                'lookup_field': 'uuid'
            }
        }
        protected_fields = ('service', 'default_price_list_item')

    def create(self, validated_data):
        try:
            return super(PriceListItemSerializer, self).create(validated_data)
        except IntegrityError:
            raise serializers.ValidationError(
                _('Price list item for service already exists.'))
예제 #4
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):
        alert, _ = log.AlertLogger().process(
            severity=validated_data['severity'],
            message_template=validated_data['message'],
            scope=validated_data['scope'],
            alert_type=validated_data['alert_type'],
        )
        return alert
예제 #5
0
class QuotaSerializer(serializers.HyperlinkedModelSerializer):
    scope = GenericRelatedField(related_models=utils.get_models_with_quotas(), read_only=True)

    class Meta(object):
        model = models.Quota
        fields = ('url', 'uuid', 'name', 'limit', 'usage', 'scope')
        read_only_fields = ('uuid', 'name', 'usage')
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
        }
예제 #6
0
class BackupSerializer(serializers.HyperlinkedModelSerializer):
    backup_source = GenericRelatedField(related_models=utils.get_backupable_models())
    state = serializers.ReadOnlyField(source='get_state_display')
    backup_source_name = serializers.ReadOnlyField(source='backup_source.name')
    metadata = JsonField(read_only=True)

    class Meta(object):
        model = models.Backup
        fields = ('url', 'uuid', 'description', 'created_at', 'kept_until', 'backup_source', 'state', 'backup_schedule',
                  'metadata', 'backup_source_name')
        read_only_fields = ('created_at', 'kept_until', 'backup_schedule')
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
            'backup_schedule': {'lookup_field': 'uuid'},
        }
예제 #7
0
class BackupScheduleSerializer(serializers.HyperlinkedModelSerializer):
    backup_source = GenericRelatedField(related_models=utils.get_backupable_models())
    backup_source_name = serializers.ReadOnlyField(source='backup_source.name')
    timezone = serializers.ChoiceField(choices=[(t, t) for t in pytz.all_timezones],
                                       default=django_timezone.get_current_timezone_name)

    class Meta(object):
        model = models.BackupSchedule
        fields = ('url', 'uuid', 'description', 'backups', 'retention_time', 'timezone',
                  'backup_source', 'maximal_number_of_backups', 'schedule', 'is_active', 'backup_source_name')
        read_only_fields = ('is_active', 'backups')
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
            'backups': {'lookup_field': 'uuid'},
        }
예제 #8
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
예제 #9
0
class PriceEstimateSerializer(AugmentedSerializerMixin,
                              serializers.HyperlinkedModelSerializer):
    scope = GenericRelatedField(
        related_models=models.PriceEstimate.get_editable_estimated_models())
    scope_name = serializers.SerializerMethodField()
    scope_type = serializers.SerializerMethodField()

    class Meta(object):
        model = models.PriceEstimate
        fields = ('url', 'uuid', 'scope', 'total', 'details', 'month', 'year',
                  'is_manually_input', 'scope_name', 'scope_type')
        read_only_fields = ('is_manually_input', )
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid'
            },
        }
        protected_fields = ('scope', 'year', 'month')

    def validate(self, data):
        if self.instance is None and models.PriceEstimate.objects.filter(
                scope=data['scope'],
                year=data['year'],
                month=data['month'],
                is_manually_input=True).exists():
            raise serializers.ValidationError(
                'Estimate for given month already exists. Use PATCH request to update it.'
            )
        return data

    def create(self, validated_data):
        validated_data['is_manually_input'] = True
        price_estimate = super(PriceEstimateSerializer,
                               self).create(validated_data)
        return price_estimate

    def get_scope_name(self, obj):
        return str(obj.scope)

    def get_scope_type(self, obj):
        models = (structure_models.Resource, structure_models.Service,
                  structure_models.ServiceProjectLink,
                  structure_models.Project, structure_models.Customer)
        for model in models:
            if isinstance(obj.scope, model):
                return model._meta.model_name
예제 #10
0
class PriceListItemSerializer(serializers.HyperlinkedModelSerializer):
    service = GenericRelatedField(
        related_models=structure_models.Service.get_all_models())

    class Meta:
        model = models.PriceListItem
        fields = ('url', 'uuid', 'key', 'item_type', 'value', 'units',
                  'service')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid'
            },
        }

    def create(self, validated_data):
        # XXX: This behavior is wrong for services with several resources, find a better approach
        resource_class = SupportedServices.get_related_models(
            validated_data['service'])['resources'][0]
        validated_data[
            'resource_content_type'] = ContentType.objects.get_for_model(
                resource_class)
        return super(PriceListItemSerializer, self).create(validated_data)
예제 #11
0
class PriceEstimateSerializer(AugmentedSerializerMixin,
                              serializers.HyperlinkedModelSerializer):
    scope = GenericRelatedField(
        related_models=models.PriceEstimate.get_estimated_models())
    scope_name = serializers.SerializerMethodField()
    scope_type = serializers.SerializerMethodField()
    resource_type = serializers.SerializerMethodField()
    consumption_details = serializers.SerializerMethodField(
        help_text=_('How much of each consumables were used by resource.'))

    def __init__(self, *args, **kwargs):
        depth = kwargs.get('context',
                           {}).pop('depth',
                                   0)  # allow to modify depth dynamically
        self.Meta.depth = depth
        super(PriceEstimateSerializer, self).__init__(*args, **kwargs)

    class Meta(object):
        model = models.PriceEstimate
        fields = ('url', 'uuid', 'scope', 'total', 'consumed', 'month', 'year',
                  'scope_name', 'scope_type', 'resource_type',
                  'consumption_details', 'children')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid'
            },
        }

    def get_fields(self):
        display_children = self.Meta.depth > 0
        fields = super(PriceEstimateSerializer, self).get_fields()
        if not display_children:
            del fields['children']
        return fields

    def build_nested_field(self, field_name, relation_info, nested_depth):
        """ Use PriceEstimateSerializer to serialize estimate children """
        if field_name != 'children':
            return super(PriceEstimateSerializer,
                         self).build_nested_field(field_name, relation_info,
                                                  nested_depth)
        field_class = self.__class__
        field_kwargs = {
            'read_only': True,
            'many': True,
            'context': {
                'depth': nested_depth - 1
            }
        }
        return field_class, field_kwargs

    def get_scope_name(self, obj):
        if obj.scope:
            return getattr(obj.scope, 'name', six.text_type(obj.scope))
        if obj.details:
            return obj.details.get('scope_name')

    def get_scope_type(self, obj):
        return ScopeTypeFilterBackend.get_scope_type(
            obj.content_type.model_class())

    def get_resource_type(self, obj):
        if obj.is_resource_estimate():
            return SupportedServices.get_name_for_model(
                obj.content_type.model_class())

    def get_consumption_details(self, obj):
        try:
            consumption_details = obj.consumption_details
        except models.ConsumptionDetails.DoesNotExist:
            return
        consumed_in_month = consumption_details.consumed_in_month
        consumable_items = consumed_in_month.keys()
        pretty_names = models.DefaultPriceListItem.get_consumable_items_pretty_names(
            obj.content_type, consumable_items)
        return {
            pretty_names[item]: consumed_in_month[item]
            for item in consumable_items
        }
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(),
        write_only=True)

    # visible name could be populated from scope, so we need to mark it as not required
    visible_name = serializers.CharField(required=False)
    scope = GenericRelatedField(
        related_models=structure_models.Resource.get_all_models(),
        required=False)
    templates = NestedTemplateSerializer(
        queryset=models.Template.objects.all().select_related('items'),
        many=True,
        required=False)
    agreed_sla = serializers.FloatField()
    actual_sla = serializers.SerializerMethodField()

    class Meta(structure_serializers.BaseResourceSerializer.Meta):
        model = models.Host
        view_name = 'zabbix-host-detail'
        fields = structure_serializers.BaseResourceSerializer.Meta.fields + (
            'visible_name', 'interface_parameters', 'host_group_name', 'scope',
            'templates', 'agreed_sla', 'actual_sla')

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

    def validate(self, attrs):
        # initiate name and visible name from scope if it is defined and check that they are not empty
        if 'scope' in attrs:
            attrs['visible_name'] = models.Host.get_visible_name_from_scope(
                attrs['scope'])
        if not attrs.get('visible_name') and self.instance is None:
            raise serializers.ValidationError(
                'Visible name or scope should be defined.')
        # forbid templates update
        if self.instance is not None and 'templates' in attrs:
            raise serializers.ValidationError(
                'Its impossible to update host templates')
        # model validation
        if self.instance is not None:
            for name, value in attrs.items():
                setattr(self.instance, name, value)
            self.instance.clean()
        else:
            instance = models.Host(
                **{k: v
                   for k, v in attrs.items() if k != 'templates'})
            instance.clean()
        return attrs

    def create(self, validated_data):
        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_names = host.service_project_link.service.settings.options.get(
                    'templates_names',
                    backend.ZabbixRealBackend.DEFAULT_TEMPLATES_NAMES)
                templates = models.Template.objects.filter(
                    settings=host.service_project_link.service.settings,
                    name__in=templates_names)
            for template in templates:
                host.templates.add(template)

        return host

    def get_actual_sla(self, host):
        if 'sla_map' not in self.context:
            period = self.context.get('period')
            if period is None:
                raise AttributeError(
                    'HostSerializer has to be initialized with `period` in context'
                )
            qs = models.SlaHistory.objects.filter(period=period)
            if isinstance(self.instance, list):
                qs = qs.filter(host__in=self.instance)
            else:
                qs = qs.filter(host=self.instance)
            self.context['sla_map'] = {q.host_id: q.value for q in qs}

        return self.context['sla_map'].get(host.id)
예제 #13
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)