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
class NestedCloudProjectMembershipSerializer(structure_serializers.PermissionFieldFilteringMixin, core_serializers.AugmentedSerializerMixin, core_serializers.HyperlinkedRelatedModelSerializer): quotas = quotas_serializers.QuotaSerializer(many=True, read_only=True) state = MappedChoiceField( choices=[(v, k) for k, v in core_models.SynchronizationStates.CHOICES], choice_mappings={v: k for k, v in core_models.SynchronizationStates.CHOICES}, read_only=True, ) class Meta(object): model = models.CloudProjectMembership fields = ( 'url', 'project', 'project_name', 'project_uuid', 'cloud', 'cloud_name', 'cloud_uuid', 'quotas', 'state', ) view_name = 'cloudproject_membership-detail' extra_kwargs = { 'cloud': {'lookup_field': 'uuid'}, 'project': {'lookup_field': 'uuid'}, } def run_validators(self, value): # No need to validate any fields except 'url' that is validated in to_internal_value method pass def get_filtered_field_names(self): return 'project', 'cloud' def get_related_paths(self): return 'project', 'cloud'
class WebHookSerializer(BaseHookSerializer): content_type = MappedChoiceField( choices=[(v, v) for k, v in models.WebHook.ContentTypeChoices.CHOICES], choice_mappings={v: k for k, v in models.WebHook.ContentTypeChoices.CHOICES}, required=False ) class Meta(BaseHookSerializer.Meta): model = models.WebHook fields = BaseHookSerializer.Meta.fields + ('destination_url', 'content_type') def get_hook_type(self, hook): return 'webhook'
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
class SecurityGroupSerializer(core_serializers.AugmentedSerializerMixin, structure_serializers.BasePropertySerializer): SERVICE_TYPE = SupportedServices.Types.OpenStack state = MappedChoiceField( choices=[(v, k) for k, v in core_models.SynchronizationStates.CHOICES], choice_mappings={ v: k for k, v in core_models.SynchronizationStates.CHOICES }, read_only=True, ) rules = NestedSecurityGroupRuleSerializer(many=True) service_project_link = NestedServiceProjectLinkSerializer( queryset=models.OpenStackServiceProjectLink.objects.all()) class Meta(object): model = models.SecurityGroup fields = ('url', 'uuid', 'state', 'name', 'description', 'rules', 'service_project_link') read_only_fields = ('url', 'uuid') extra_kwargs = { 'url': { 'lookup_field': 'uuid' }, 'service_project_link': { 'view_name': 'openstack-spl-detail' } } view_name = 'openstack-sgp-detail' protected_fields = ('service_project_link', ) def validate(self, attrs): if self.instance is None: # Check security groups quotas on creation service_project_link = attrs.get('service_project_link') security_group_count_quota = service_project_link.quotas.get( name='security_group_count') if security_group_count_quota.is_exceeded(delta=1): raise serializers.ValidationError( 'Can not create new security group - amount quota exceeded' ) security_group_rule_count_quota = service_project_link.quotas.get( name='security_group_rule_count') if security_group_rule_count_quota.is_exceeded( delta=len(attrs.get('rules', []))): raise serializers.ValidationError( 'Can not create new security group - rules amount quota exceeded' ) else: # Check security_groups quotas on update service_project_link = self.instance.service_project_link new_rules_count = len(attrs.get('rules', [])) - self.instance.rules.count() if new_rules_count > 0: security_group_rule_count_quota = service_project_link.quotas.get( name='security_group_rule_count') if security_group_rule_count_quota.is_exceeded( delta=new_rules_count): raise serializers.ValidationError( 'Can not update new security group rules - rules amount quota exceeded' ) return attrs def validate_rules(self, value): for rule in value: rule.full_clean(exclude=['security_group']) if rule.id is not None and self.instance is None: raise serializers.ValidationError( 'Cannot add existed rule with id %s to new security group' % rule.id) elif rule.id is not None and self.instance is not None and rule.security_group != self.instance: raise serializers.ValidationError( 'Cannot add rule with id {} to group {} - it already belongs to ' 'other group' % (rule.id, self.isntance.name)) return value def create(self, validated_data): rules = validated_data.pop('rules', []) with transaction.atomic(): security_group = super(SecurityGroupSerializer, self).create(validated_data) for rule in rules: security_group.rules.add(rule) return security_group def update(self, instance, validated_data): rules = validated_data.pop('rules', []) new_rules = [rule for rule in rules if rule.id is None] existed_rules = set([rule for rule in rules if rule.id is not None]) security_group = super(SecurityGroupSerializer, self).update(instance, validated_data) old_rules = set(security_group.rules.all()) with transaction.atomic(): removed_rules = old_rules - existed_rules for rule in removed_rules: rule.delete() for rule in new_rules: security_group.rules.add(rule) return security_group
class ProjectGroupPermissionSerializer(PermissionFieldFilteringMixin, core_serializers.AugmentedSerializerMixin, serializers.HyperlinkedModelSerializer): project_group = serializers.HyperlinkedRelatedField( source='group.projectgrouprole.project_group', view_name='projectgroup-detail', lookup_field='uuid', queryset=models.ProjectGroup.objects.all(), ) role = MappedChoiceField( source='group.projectgrouprole.role_type', choices=( ('manager', 'Manager'), ), choice_mappings={ 'manager': models.ProjectGroupRole.MANAGER, }, ) class Meta(object): model = User.groups.through fields = ( 'url', 'role', 'project_group', 'project_group_name', 'user', 'user_full_name', 'user_native_name', 'user_username', ) related_paths = { 'user': ('username', 'full_name', 'native_name'), 'group.projectgrouprole.project_group': ('name',) } extra_kwargs = { 'user': { 'view_name': 'user-detail', 'lookup_field': 'uuid', 'queryset': User.objects.all(), }, } view_name = 'projectgroup_permission-detail' def create(self, validated_data): project_group = validated_data['project_group'] user = validated_data['user'] role = validated_data['role'] permission, _ = project_group.add_user(user, role) return permission def to_internal_value(self, data): value = super(ProjectGroupPermissionSerializer, self).to_internal_value(data) return { 'user': value['user'], 'project_group': value['group']['projectgrouprole']['project_group'], 'role': value['group']['projectgrouprole']['role_type'], } def validate(self, data): project_group = data['project_group'] user = data['user'] role = data['role'] if project_group.has_user(user, role): raise serializers.ValidationError('The fields project_group, user, role must make a unique set.') return data def get_filtered_field_names(self): return 'project_group',
class CustomerPermissionSerializer(PermissionFieldFilteringMixin, core_serializers.AugmentedSerializerMixin, serializers.HyperlinkedModelSerializer): customer = serializers.HyperlinkedRelatedField( source='group.customerrole.customer', view_name='customer-detail', lookup_field='uuid', queryset=models.Customer.objects.all(), ) role = MappedChoiceField( source='group.customerrole.role_type', choices=( ('owner', 'Owner'), ), choice_mappings={ 'owner': models.CustomerRole.OWNER, }, ) class Meta(object): model = User.groups.through fields = ( 'url', 'role', 'customer', 'customer_name', 'customer_native_name', 'customer_abbreviation', 'user', 'user_full_name', 'user_native_name', 'user_username', ) related_paths = { 'user': ('username', 'full_name', 'native_name'), 'group.customerrole.customer': ('name', 'native_name', 'abbreviation') } extra_kwargs = { 'user': { 'view_name': 'user-detail', 'lookup_field': 'uuid', 'queryset': User.objects.all(), }, } view_name = 'customer_permission-detail' def create(self, validated_data): customer = validated_data['customer'] user = validated_data['user'] role = validated_data['role'] permission, _ = customer.add_user(user, role) return permission def to_internal_value(self, data): value = super(CustomerPermissionSerializer, self).to_internal_value(data) return { 'user': value['user'], 'customer': value['group']['customerrole']['customer'], 'role': value['group']['customerrole']['role_type'], } def validate(self, data): customer = data['customer'] user = data['user'] role = data['role'] if customer.has_user(user, role): raise serializers.ValidationError('The fields customer, user, role must make a unique set.') return data def get_filtered_field_names(self): return 'customer',
class SecurityGroupSerializer(serializers.HyperlinkedModelSerializer): state = MappedChoiceField( choices=[(v, k) for k, v in core_models.SynchronizationStates.CHOICES], choice_mappings={v: k for k, v in core_models.SynchronizationStates.CHOICES}, read_only=True, ) rules = NestedSecurityGroupRuleSerializer(many=True) cloud_project_membership = NestedCloudProjectMembershipSerializer( queryset=models.CloudProjectMembership.objects.all()) class Meta(object): model = models.SecurityGroup fields = ('url', 'uuid', 'state', 'name', 'description', 'rules', 'cloud_project_membership') read_only_fields = ('url', 'uuid') extra_kwargs = { 'url': {'lookup_field': 'uuid'}, 'cloud_project_membership': {'view_name': 'cloudproject_membership-detail'} } view_name = 'security_group-detail' def validate(self, attrs): if attrs.get('cloud_project_membership') and self.instance is not None: raise serializers.ValidationError('Security group cloud_project_membership can not be updated') if self.instance is None: # Check security groups quotas on creation cloud_project_membership = attrs.get('cloud_project_membership') security_group_count_quota = cloud_project_membership.quotas.get(name='security_group_count') if security_group_count_quota.is_exceeded(delta=1): raise serializers.ValidationError('Can not create new security group - amount quota exceeded') security_group_rule_count_quota = cloud_project_membership.quotas.get(name='security_group_rule_count') if security_group_rule_count_quota.is_exceeded(delta=len(attrs.get('rules', []))): raise serializers.ValidationError('Can not create new security group - rules amount quota exceeded') else: # Check security_groups quotas on update cloud_project_membership = self.instance.cloud_project_membership new_rules_count = len(attrs.get('rules', [])) - self.instance.rules.count() if new_rules_count > 0: security_group_rule_count_quota = cloud_project_membership.quotas.get(name='security_group_rule_count') if security_group_rule_count_quota.is_exceeded(delta=new_rules_count): raise serializers.ValidationError( 'Can not update new security group rules - rules amount quota exceeded') return attrs def validate_rules(self, value): for rule in value: rule.full_clean(exclude=['group']) if rule.id is not None and self.instance is None: raise serializers.ValidationError('Cannot add existed rule with id %s to new security group' % rule.id) elif rule.id is not None and self.instance is not None and rule.group != self.instance: raise serializers.ValidationError('Cannot add rule with id {} to group {} - it already belongs to ' 'other group' % (rule.id, self.isntance.name)) return value def create(self, validated_data): rules = validated_data.pop('rules', []) with transaction.atomic(): security_group = super(SecurityGroupSerializer, self).create(validated_data) for rule in rules: security_group.rules.add(rule) return security_group def update(self, instance, validated_data): rules = validated_data.pop('rules', []) new_rules = [rule for rule in rules if rule.id is None] existed_rules = set([rule for rule in rules if rule.id is not None]) security_group = super(SecurityGroupSerializer, self).update(instance, validated_data) old_rules = set(security_group.rules.all()) with transaction.atomic(): removed_rules = old_rules - existed_rules for rule in removed_rules: rule.delete() for rule in new_rules: security_group.rules.add(rule) return security_group
class CloudProjectMembershipSerializer(structure_serializers.PermissionFieldFilteringMixin, core_serializers.AugmentedSerializerMixin, serializers.HyperlinkedModelSerializer): quotas = quotas_serializers.QuotaSerializer(many=True, read_only=True) state = MappedChoiceField( choices=[(v, k) for k, v in core_models.SynchronizationStates.CHOICES], choice_mappings={v: k for k, v in core_models.SynchronizationStates.CHOICES}, read_only=True, ) service_name = serializers.ReadOnlyField(source='cloud.name') service_uuid = serializers.ReadOnlyField(source='cloud.uuid') # XXX: This field is for portal only project_group = serializers.SerializerMethodField() project_group_name = serializers.SerializerMethodField() project_group_uuid = serializers.SerializerMethodField() class Meta(object): model = models.CloudProjectMembership fields = ( 'url', 'project', 'project_name', 'project_uuid', 'project_group', 'project_group_name', 'project_group_uuid', 'cloud', 'cloud_name', 'cloud_uuid', 'quotas', 'state', 'tenant_id', 'service_name', 'service_uuid', 'external_network_id', 'internal_network_id', ) read_only_fields = ('external_network_id', 'internal_network_id',) view_name = 'cloudproject_membership-detail' extra_kwargs = { 'cloud': {'lookup_field': 'uuid'}, 'project': {'lookup_field': 'uuid'}, } # XXX: This field is for portal only def get_project_group(self, obj): if obj.project.project_group is not None: url = reverse('projectgroup-detail', kwargs={'uuid': obj.project.project_group.uuid}) try: return self.context['request'].build_absolute_uri(url) except KeyError: return url # XXX: This field is for portal only def get_project_group_name(self, obj): if obj.project.project_group is not None: return obj.project.project_group.name # XXX: This field is for portal only def get_project_group_uuid(self, obj): if obj.project.project_group is not None: return obj.project.project_group.uuid.hex def get_filtered_field_names(self): return 'project', 'cloud' def get_related_paths(self): return 'project', 'cloud' def validate(self, attrs): if attrs['cloud'].customer != attrs['project'].customer: raise serializers.ValidationError("Cloud customer doesn't match project customer") return attrs def save(self, **kwargs): try: return super(CloudProjectMembershipSerializer, self).save(**kwargs) except IntegrityError: # unique constraint validation # TODO: Should be done on a higher level raise UniqueConstraintError()