class CatalogSerializer(serializers.HyperlinkedModelSerializer):
    scope = core_serializers.GenericRelatedField()

    class Meta:
        model = models.Catalog
        fields = (
            'uuid',
            'url',
            'created',
            'modified',
            'name',
            'description',
            'catalog_url',
            'branch',
            'commit',
            'runtime_state',
            'scope',
            'scope_type',
        )
        read_only_fields = ('runtime_state', 'commit')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-catalog-detail'
            },
        }
Esempio n. 2
0
 def get_resource_by_url(self, request, resource_url):
     related_models = structure_models.VirtualMachine.get_all_models()
     field = core_serializers.GenericRelatedField(
         related_models=related_models)
     # Trick to set field context without serializer
     field._context = {'request': request}
     return field.to_internal_value(resource_url)
Esempio n. 3
0
class NestedNodeSerializer(serializers.HyperlinkedModelSerializer):
    instance = core_serializers.GenericRelatedField(
        related_models=VirtualMachine.get_all_models(), read_only=True)

    subnet = serializers.HyperlinkedRelatedField(
        view_name='openstacktenant-subnet-detail',
        queryset=openstack_tenant_models.SubNet.objects.all(),
        lookup_field='uuid',
        allow_null=True,
        write_only=True,
    )
    storage = serializers.IntegerField(write_only=True)
    memory = serializers.IntegerField(write_only=True)
    cpu = serializers.IntegerField(write_only=True)
    roles = serializers.MultipleChoiceField(
        choices=['controlplane', 'etcd', 'worker'], write_only=True)

    class Meta(object):
        model = models.Node
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-node-detail'
            },
            'cluster': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-cluster-detail'
            }
        }
        exclude = ('cluster', 'object_id', 'content_type')
Esempio n. 4
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. 5
0
class NodeSerializer(serializers.HyperlinkedModelSerializer):
    instance = core_serializers.GenericRelatedField(
        related_models=VirtualMachine.get_all_models(),
        required=True,
    )

    class Meta:
        model = models.Node
        fields = ('uuid', 'url', 'created', 'modified', 'cluster', 'instance',
                  'controlplane_role', 'etcd_role', 'worker_role',
                  'get_node_command')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-node-detail'
            },
            'cluster': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-cluster-detail'
            }
        }

    def validate(self, attrs):
        instance = attrs.get('instance')

        if models.Node.objects.filter(
                object_id=instance.id,
                content_type=ContentType.objects.get_for_model(
                    instance)).exists():
            raise serializers.ValidationError(
                {'instance': 'The selected instance is already in use.'})

        return super(NodeSerializer, self).validate(attrs)
Esempio n. 6
0
class ResourceSerializer(BaseItemSerializer):
    class Meta(BaseItemSerializer.Meta):
        model = models.Resource
        fields = BaseItemSerializer.Meta.fields + (
            'scope', 'state', 'resource_uuid', 'resource_type',
            'project', 'project_uuid', 'project_name',
            'customer_uuid', 'customer_name',
            'offering_uuid', 'offering_name',
            'backend_metadata', 'is_usage_based',
        )
        read_only_fields = ('backend_metadata', 'scope',)

    state = serializers.ReadOnlyField(source='get_state_display')
    scope = core_serializers.GenericRelatedField()
    resource_uuid = serializers.ReadOnlyField(source='backend_uuid')
    resource_type = serializers.ReadOnlyField(source='backend_type')
    project = serializers.HyperlinkedRelatedField(
        lookup_field='uuid',
        view_name='project-detail',
        read_only=True,
    )
    project_uuid = serializers.ReadOnlyField(source='project.uuid')
    project_name = serializers.ReadOnlyField(source='project.name')
    customer_uuid = serializers.ReadOnlyField(source='project.customer.uuid')
    customer_name = serializers.ReadOnlyField(source='project.customer.name')
    offering_uuid = serializers.ReadOnlyField(source='offering.uuid')
    offering_name = serializers.ReadOnlyField(source='offering.name')
    # If resource is usage-based, frontend would render button to show and report usage
    is_usage_based = serializers.ReadOnlyField(source='offering.is_usage_based')
Esempio n. 7
0
 def filter_queryset(self, request, queryset, view):
     value = self.get_field_value(request)
     if value:
         field = core_serializers.GenericRelatedField(related_models=self.get_related_models())
         # Trick to set field context without serializer
         field._context = {'request': request}
         obj = field.to_internal_value(value)
         ct = ContentType.objects.get_for_model(obj)
         return queryset.filter(**{self.object_id_field: obj.id, self.content_type_field: ct})
     return queryset
class NestedNodeSerializer(BaseNodeSerializer):
    instance = core_serializers.GenericRelatedField(
        related_models=VirtualMachine.get_all_models(), read_only=True)

    class Meta(BaseNodeSerializer.Meta):
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-node-detail'
            },
            'cluster': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-cluster-detail'
            },
        }
        exclude = ('cluster', 'object_id', 'content_type', 'name')
Esempio n. 9
0
class PriceEstimateSerializer(serializers.HyperlinkedModelSerializer):
    scope = core_serializers.GenericRelatedField(
        related_models=models.PriceEstimate.get_estimated_models(),
        required=False)
    scope_name = serializers.ReadOnlyField(source='scope.name')
    scope_uuid = serializers.ReadOnlyField(source='scope.uuid')

    class Meta(object):
        model = models.PriceEstimate
        fields = ('url', 'uuid', 'scope', 'scope_name', 'scope_uuid', 'limit',
                  'total', 'threshold')
        read_only_fields = ('total', 'scope')
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid'
            },
        }

    def validate(self, attrs):
        if 'limit' in attrs:
            if isinstance(self.instance.scope, structure_models.Project):
                self._validate_project_limit(self.instance.scope,
                                             attrs['limit'])

            if isinstance(self.instance.scope, structure_models.Customer):
                self._validate_customer_limit(self.instance.scope,
                                              attrs['limit'])

        return attrs

    def _validate_project_limit(self, project, limit):
        customer = project.customer

        customer_limit = self._get_customer_limit(customer)
        if customer_limit == -1:
            return

        total_limit = self._get_total_limit(
            customer.projects.exclude(uuid=project.uuid)) + limit

        if total_limit > customer_limit:
            message = _(
                'Total price limits of projects exceeds organization price limit. '
                'Total limit: %(total_limit)s, organization limit: %(customer_limit)s'
            )
            context = dict(total_limit=total_limit,
                           customer_limit=customer_limit)
            raise serializers.ValidationError({'limit': message % context})

    def _validate_customer_limit(self, customer, limit):
        if limit == -1:
            return

        total_limit = self._get_total_limit(customer.projects.all())

        if limit < total_limit:
            message = _(
                'Organization limit cannot be less than a sum of its projects limits: %d'
            )
            raise serializers.ValidationError({'limit': message % total_limit})

    def _get_customer_limit(self, customer):
        try:
            estimate = models.PriceEstimate.objects.get(scope=customer)
            return estimate.limit
        except models.PriceEstimate.DoesNotExist:
            return -1

    def _get_total_limit(self, projects):
        if not projects.exists():
            return 0
        estimates = models.PriceEstimate.objects.filter(
            scope__in=projects).exclude(limit=-1)
        return estimates.aggregate(Sum('limit'))['limit__sum'] or 0
Esempio n. 10
0
class IssueSerializer(core_serializers.AugmentedSerializerMixin,
                      serializers.HyperlinkedModelSerializer):
    resource = core_serializers.GenericRelatedField(
        related_models=structure_models.ResourceMixin.get_all_models(), required=False)
    caller = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='uuid',
        queryset=User.objects.all(),
        required=False,
        allow_null=True,
    )
    reporter = serializers.HyperlinkedRelatedField(
        view_name='support-user-detail',
        lookup_field='uuid',
        read_only=True
    )
    assignee = serializers.HyperlinkedRelatedField(
        view_name='support-user-detail',
        lookup_field='uuid',
        queryset=models.SupportUser.objects.all(),
        required=False,
        allow_null=True,
    )
    template = serializers.HyperlinkedRelatedField(
        view_name='support-template-detail',
        lookup_field='uuid',
        queryset=models.Template.objects.all(),
        required=False,
        allow_null=True,
    )
    resource_type = serializers.SerializerMethodField()
    resource_name = serializers.ReadOnlyField(source='resource.name')
    type = serializers.ChoiceField(
        choices=[(t, t) for t in settings.WALDUR_SUPPORT['ISSUE']['types']],
        initial=settings.WALDUR_SUPPORT['ISSUE']['types'][0],
        default=settings.WALDUR_SUPPORT['ISSUE']['types'][0])
    is_reported_manually = serializers.BooleanField(
        initial=False, default=False, write_only=True,
        help_text=_('Set true if issue is created by regular user via portal.'))

    class Meta:
        model = models.Issue
        fields = (
            'url', 'uuid', 'type', 'key', 'backend_id', 'link',
            'summary', 'description', 'status', 'resolution', 'priority',
            'caller', 'caller_uuid', 'caller_full_name',
            'reporter', 'reporter_uuid', 'reporter_name',
            'assignee', 'assignee_uuid', 'assignee_name',
            'customer', 'customer_uuid', 'customer_name',
            'project', 'project_uuid', 'project_name',
            'resource', 'resource_type', 'resource_name',
            'created', 'modified', 'is_reported_manually',
            'first_response_sla', 'template'
        )
        read_only_fields = ('key', 'status', 'resolution', 'backend_id', 'link', 'first_response_sla')
        protected_fields = ('customer', 'project', 'resource', 'type', 'caller', 'template', 'priority')
        extra_kwargs = dict(
            url={'lookup_field': 'uuid'},
            customer={'lookup_field': 'uuid', 'view_name': 'customer-detail'},
            project={'lookup_field': 'uuid', 'view_name': 'project-detail'},
        )
        related_paths = dict(
            caller=('uuid', 'full_name',),
            reporter=('uuid', 'name',),
            assignee=('uuid', 'name',),
            customer=('uuid', 'name',),
            project=('uuid', 'name',),
        )

    def get_fields(self):
        fields = super(IssueSerializer, self).get_fields()

        if 'view' not in self.context:  # On docs generation context does not contain "view".
            return fields

        user = self.context['view'].request.user
        if not user.is_staff and not user.is_support:
            del fields['link']

        return fields

    def get_resource_type(self, obj):
        if isinstance(obj.resource, structure_models.ResourceMixin):
            return SupportedServices.get_name_for_model(obj.resource_content_type.model_class())

    def validate(self, attrs):
        if self.instance is not None:
            return attrs
        if attrs.pop('is_reported_manually'):
            attrs['caller'] = self.context['request'].user
            if attrs.get('assignee'):
                raise serializers.ValidationError(
                    {'assignee': _('Assignee cannot be defined if issue is reported manually.')})
        else:
            if not attrs.get('caller'):
                raise serializers.ValidationError({'caller': _('This field is required.')})
            reporter = models.SupportUser.objects.filter(
                user=self.context['request'].user, is_active=True).first()
            if not reporter:
                raise serializers.ValidationError(
                    _('You cannot report issues because your help desk account is not connected to profile.'))
            attrs['reporter'] = reporter
        return attrs

    def validate_customer(self, customer):
        """ User has to be customer owner, staff or global support """
        if not customer:
            return customer
        user = self.context['request'].user
        if (not customer or
                user.is_staff or
                user.is_support or
                customer.has_user(user, structure_models.CustomerRole.OWNER)):
            return customer
        raise serializers.ValidationError(_('Only customer owner, staff or support can report customer issues.'))

    def validate_project(self, project):
        if not project:
            return project
        user = self.context['request'].user
        if (not project or
                user.is_staff or
                user.is_support or
                project.customer.has_user(user, structure_models.CustomerRole.OWNER) or
                project.has_user(user, structure_models.ProjectRole.MANAGER) or
                project.has_user(user, structure_models.ProjectRole.ADMINISTRATOR)):
            return project
        raise serializers.ValidationError(
            _('Only customer owner, project manager, project admin, staff or support can report such issue.'))

    def validate_resource(self, resource):
        if resource:
            self.validate_project(resource.service_project_link.project)
        return resource

    def validate_priority(self, priority):
        user = self.context['request'].user
        if not user.is_staff and not user.is_support:
            raise serializers.ValidationError(_('Only staff or support can specify issue priority.'))
        try:
            models.Priority.objects.get(name=priority)
        except (models.Priority.DoesNotExist, models.Priority.MultipleObjectsReturned):
            raise serializers.ValidationError(_('Priority with requested name does not exist.'))
        return priority

    @transaction.atomic()
    def create(self, validated_data):
        resource = validated_data.get('resource')
        if resource:
            validated_data['project'] = resource.service_project_link.project
        project = validated_data.get('project')
        if project:
            validated_data['customer'] = project.customer

        validated_data['description'] = render_issue_template('description', validated_data)
        validated_data['summary'] = render_issue_template('summary', validated_data)
        return super(IssueSerializer, self).create(validated_data)

    def _render_template(self, config_name, issue):
        raw = self.issue_settings[config_name]
        template = Template(raw)
        return template.render(Context({'issue': issue}))
Esempio n. 11
0
class NodeSerializer(serializers.HyperlinkedModelSerializer):
    instance = core_serializers.GenericRelatedField(
        related_models=VirtualMachine.get_all_models(),
        required=True,
    )
    resource_type = serializers.SerializerMethodField()
    state = serializers.ReadOnlyField(source='get_state_display')
    service_name = serializers.ReadOnlyField(
        source='service_project_link.service.settings.name')
    service_uuid = serializers.ReadOnlyField(
        source='service_project_link.service.uuid')
    project_uuid = serializers.ReadOnlyField(
        source='service_project_link.project.uuid')
    cluster_name = serializers.ReadOnlyField(source='cluster.name')
    cluster_uuid = serializers.ReadOnlyField(source='cluster.uuid')
    instance_name = serializers.ReadOnlyField(source='instance.name')
    instance_uuid = serializers.ReadOnlyField(source='instance.uuid')

    class Meta:
        model = models.Node
        fields = (
            'uuid',
            'url',
            'created',
            'modified',
            'name',
            'backend_id',
            'project_uuid',
            'service_name',
            'service_uuid',
            'resource_type',
            'state',
            'cluster',
            'cluster_name',
            'cluster_uuid',
            'instance',
            'instance_name',
            'instance_uuid',
            'controlplane_role',
            'etcd_role',
            'worker_role',
            'get_node_command',
            'k8s_version',
            'docker_version',
            'cpu_allocated',
            'cpu_total',
            'ram_allocated',
            'ram_total',
            'pods_allocated',
            'pods_total',
            'labels',
            'annotations',
            'runtime_state',
        )
        read_only_fields = (
            'backend_id',
            'k8s_version',
            'docker_version',
            'cpu_allocated',
            'cpu_total',
            'ram_allocated',
            'ram_total',
            'pods_allocated',
            'pods_total',
            'labels',
            'annotations',
            'runtime_state',
        )
        extra_kwargs = {
            'url': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-node-detail'
            },
            'cluster': {
                'lookup_field': 'uuid',
                'view_name': 'rancher-cluster-detail'
            },
        }

    def validate(self, attrs):
        instance = attrs.get('instance')

        if models.Node.objects.filter(
                object_id=instance.id,
                content_type=ContentType.objects.get_for_model(instance),
        ).exists():
            raise serializers.ValidationError(
                {'instance': 'The selected instance is already in use.'})

        attrs['name'] = instance.name

        return super(NodeSerializer, self).validate(attrs)

    def get_resource_type(self, obj):
        return 'Rancher.Node'
Esempio n. 12
0
class PythonManagementSerializer(
        common_serializers.BaseApplicationSerializer,
        structure_serializers.PermissionFieldFilteringMixin):
    REQUEST_IN_PROGRESS_STATES = (core_models.StateMixin.States.CREATION_SCHEDULED, core_models.StateMixin.States.CREATING)

    state = serializers.SerializerMethodField()
    virtual_environments = VirtualEnvironmentSerializer(many=True)
    virtual_envs_dir_path = serializers.CharField(max_length=255, validators=[
        RegexValidator(
            regex=directory_and_library_allowed_pattern,
            message=_('Virtual environments root directory has invalid format!'),
        ),
    ])
    name = serializers.SerializerMethodField()
    type = serializers.SerializerMethodField()

    instance = core_serializers.GenericRelatedField(
        related_models=structure_models.ResourceMixin.get_all_models(), required=False)
    instance_name = serializers.ReadOnlyField(source='instance.name')

    class Meta(object):
        model = models.PythonManagement
        fields = ('url', 'uuid', 'virtual_envs_dir_path', 'system_user',
                  'state', 'created', 'modified', 'virtual_environments', 'python_version', 'name', 'type', 'instance', 'instance_name',)
        read_only_fields = ('request_states', 'created', 'modified', 'python_version', 'type', 'name', 'url',)
        extra_kwargs = {
            'url': {'lookup_field': 'uuid'},
        }

    def get_name(self, python_management):
        instance_name = python_management.instance.name if python_management.instance else 'removed instance'
        return 'Python Management - %s - %s' % (instance_name, python_management.virtual_envs_dir_path)

    def get_type(self, python_management):
        return 'python_management'

    def get_filtered_field_names(self):
        return 'project'

    def get_state(self, python_management):
        states = []
        initialize_request = utils.execute_safely(
            lambda: models.PythonManagementInitializeRequest.objects.filter(python_management=python_management).latest('id'))
        if initialize_request and self.is_in_progress_or_errored(initialize_request):
            return [self.build_state(initialize_request)]

        states.extend(self.get_request_state(
            utils.execute_safely(lambda: models.PythonManagementDeleteRequest.objects.filter(python_management=python_management).latest('id'))))
        states.extend(
            self.get_request_state(
                utils.execute_safely(
                    lambda: models.PythonManagementDeleteVirtualEnvRequest.objects.filter(python_management=python_management).latest('id'))))
        states.extend(self.build_search_requests_states(python_management))
        states.extend(self.build_states_from_last_group_of_the_request(python_management, models.PythonManagementSynchronizeRequest))

        if not states:
            return core_models.StateMixin(state=core_models.StateMixin.States.OK).human_readable_state
        else:
            creation_scheduled_state = core_models.StateMixin(state=core_models.StateMixin.States.CREATION_SCHEDULED).human_readable_state
            creating_state = core_models.StateMixin(state=core_models.StateMixin.States.CREATING).human_readable_state
            erred_state = core_models.StateMixin(state=core_models.StateMixin.States.ERRED).human_readable_state
            if creating_state in states:
                return creating_state
            elif creation_scheduled_state in states:
                return creation_scheduled_state
            elif erred_state in states:
                return erred_state

    def build_search_requests_states(self, python_management):
        states = []
        states.extend(
            self.get_request_state(
                utils.execute_safely(
                    lambda: models.PythonManagementFindVirtualEnvsRequest.objects
                    .filter(python_management=python_management).latest('id'))))
        states.extend(self.build_states_from_last_group_of_the_request(python_management, models.PythonManagementFindInstalledLibrariesRequest))
        return states

    def get_request_state(self, request):
        if request and self.is_in_progress_or_errored(request):
            return [self.build_state(request)]
        else:
            return []

    def build_states_from_last_group_of_the_request(self, python_management, request_class):
        states = []
        requests = request_class.objects.filter(python_management=python_management).order_by('-id')
        last_request_group = self.get_last_requests_group(requests)
        for request in last_request_group:
            if self.is_in_progress_or_errored(request):
                states.append(self.build_state(request))
        return states

    def get_last_requests_group(self, requests):
        last_request_group = []

        last_request_time = None
        for request in requests:
            if not last_request_time:
                last_request_time = request.created - datetime.timedelta(minutes=1)
            if request.created < last_request_time:
                break
            last_request_group.append(request)

        return last_request_group

    def is_in_progress_or_errored(self, request):
        return request.state in PythonManagementSerializer.REQUEST_IN_PROGRESS_STATES \
            or request.state == core_models.StateMixin.States.ERRED

    def build_state(self, request, state=None):
        request_state = state if state else request
        return request_state.human_readable_state

    @transaction.atomic
    def create(self, validated_data):
        python_management = models.PythonManagement(
            user=validated_data.get('user'),
            virtual_envs_dir_path=validated_data.get('virtual_envs_dir_path'),
            instance=validated_data.get('instance'),
            project=validated_data.get('instance').service_project_link.project,
            python_version='3',
            system_user=validated_data.get('system_user'))
        python_management.save()
        return python_management

    def validate(self, attrs):
        super(PythonManagementSerializer, self).validate(attrs)
        if not self.instance:
            attrs['user'] = self.context['request'].user
            self.check_resource_type(attrs)

        self.check_project_permissions(attrs)
        return attrs

    def check_resource_type(self, attrs):
        if not issubclass(type(attrs['instance']), structure_models.VirtualMachine):
            raise exceptions.ValidationError(_('Please specify a virtual machine, not just any resource.'))

    def check_project_permissions(self, attrs):
        if self.instance:
            project = self.instance.project
        else:
            project = attrs['instance'].service_project_link.project

        if not structure_permissions._has_admin_access(self.context['request'].user, project):
            raise exceptions.PermissionDenied()
Esempio n. 13
0
class IssueSerializer(JiraPropertySerializer):
    priority = serializers.HyperlinkedRelatedField(
        view_name='jira-priorities-detail',
        queryset=models.Priority.objects.all(),
        lookup_field='uuid',
    )
    access_url = serializers.ReadOnlyField(source='get_access_url')
    comments = CommentSerializer(many=True, read_only=True)

    scope = core_serializers.GenericRelatedField(
        source='resource',
        related_models=structure_models.BaseResource.get_all_models(),
        required=False,
    )
    scope_type = serializers.SerializerMethodField()
    scope_name = serializers.ReadOnlyField(source='resource.name')

    parent = serializers.HyperlinkedRelatedField(
        view_name='jira-issues-detail',
        queryset=models.Issue.objects.all(),
        lookup_field='uuid',
        required=False,
        allow_null=True,
    )

    # For consistency with resource serializer render
    # Waldur project as project and JIRA project as jira_project
    project = serializers.HyperlinkedRelatedField(
        source='project.project',
        view_name='project-detail',
        read_only=True,
        lookup_field='uuid',
    )

    project_name = serializers.ReadOnlyField(source='project.project.name')
    project_uuid = serializers.ReadOnlyField(source='project.project.uuid')

    jira_project = serializers.HyperlinkedRelatedField(
        queryset=models.Project.objects.all(),
        source='project',
        view_name='jira-projects-detail',
        lookup_field='uuid',
    )

    jira_project_name = serializers.ReadOnlyField(source='project.name')
    jira_project_uuid = serializers.ReadOnlyField(source='project.uuid')

    resource_type = serializers.SerializerMethodField()
    service_settings_state = serializers.SerializerMethodField()

    def get_resource_type(self, obj):
        return 'JIRA.Issue'

    def get_service_settings_state(self, obj):
        return 'OK'

    def get_scope_type(self, obj):
        if obj.resource:
            return get_resource_type(obj.resource_content_type.model_class())

    class Meta(JiraPropertySerializer.Meta):
        model = models.Issue
        fields = JiraPropertySerializer.Meta.fields + (
            'project',
            'project_uuid',
            'project_name',
            'jira_project',
            'jira_project_uuid',
            'jira_project_name',
            'key',
            'summary',
            'description',
            'resolution',
            'status',
            'priority',
            'priority_name',
            'priority_icon_url',
            'priority_description',
            'created',
            'updated',
            'creator_username',
            'creator_name',
            'creator_email',
            'assignee_username',
            'assignee_name',
            'assignee_email',
            'reporter_username',
            'reporter_name',
            'reporter_email',
            'resolution_date',
            'access_url',
            'comments',
            'resource_type',
            'service_settings_state',
            'type',
            'type_name',
            'type_description',
            'type_icon_url',
            'scope',
            'scope_type',
            'scope_name',
            'parent',
            'parent_uuid',
            'parent_summary',
            'resolution_sla',
        )
        read_only_fields = (
            'status',
            'resolution',
            'updated_username',
            'error_message',
            'resolution_sla',
            'backend_id',
        )
        protected_fields = (
            'jira_project',
            'key',
            'type',
            'scope',
        )
        extra_kwargs = dict(url={
            'lookup_field': 'uuid',
            'view_name': 'jira-issues-detail'
        },
                            type={
                                'lookup_field': 'uuid',
                                'view_name': 'jira-issue-types-detail'
                            },
                            parent={
                                'lookup_field': 'uuid',
                                'view_name': 'jira-issues-detail'
                            },
                            **JiraPropertySerializer.Meta.extra_kwargs)
        related_paths = dict(type=('icon_url', 'name', 'description'),
                             parent=('uuid', 'summary'),
                             priority=('icon_url', 'name', 'description'),
                             **JiraPropertySerializer.Meta.related_paths)

    def create(self, validated_data):
        project = validated_data['project']
        issue_type = validated_data['type']
        if issue_type not in project.issue_types.all():
            valid_choices = ', '.join(
                project.issue_types.values_list('name', flat=True))
            raise serializers.ValidationError({
                'type':
                _('Invalid issue type. Please select one of following: %s') %
                valid_choices
            })

        priority = validated_data['priority']
        if priority.settings != project.service_settings:
            raise serializers.ValidationError({
                'parent':
                _('Priority should belong to the same JIRA provider.')
            })

        parent_issue = validated_data.get('parent')
        if parent_issue:
            if not issue_type.subtask:
                raise serializers.ValidationError({
                    'parent':
                    _('Issue type is not subtask, parent issue is not allowed.'
                      )
                })

            if parent_issue.project != project:
                raise serializers.ValidationError({
                    'parent':
                    _('Parent issue should belong to the same JIRA project.')
                })

        return super(IssueSerializer, self).create(validated_data)
Esempio n. 14
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
Esempio n. 15
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