mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-26 10:28:37 -06:00
Finish up add FHRP Group assignment to Service
- fixes up ServiceSerializer to support write operations - fixes up GraphQL components: ServiceType and ServiceFilter - fixes broken tests - cleans up lint issues
This commit is contained in:
parent
60e8268882
commit
0564ee9cfc
@ -613,7 +613,7 @@ class Device(
|
||||
to='ipam.Service',
|
||||
content_type_field='parent_object_type',
|
||||
object_id_field='parent_object_id',
|
||||
related_query_name='devices',
|
||||
related_query_name='device',
|
||||
)
|
||||
|
||||
# Counter fields
|
||||
|
@ -1,13 +1,13 @@
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework import serializers
|
||||
|
||||
from dcim.models import Device
|
||||
from ipam.choices import *
|
||||
from ipam.models import IPAddress, FHRPGroup, Service, ServiceTemplate
|
||||
from netbox.api.fields import ChoiceField, SerializedPKRelatedField
|
||||
from ipam.constants import SERVICE_ASSIGNMENT_MODELS
|
||||
from ipam.models import IPAddress, Service, ServiceTemplate
|
||||
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
|
||||
from netbox.api.serializers import NetBoxModelSerializer
|
||||
from utilities.api import get_serializer_for_model
|
||||
from virtualization.models import VirtualMachine
|
||||
from .ip import IPAddressSerializer
|
||||
|
||||
__all__ = (
|
||||
@ -29,9 +29,6 @@ class ServiceTemplateSerializer(NetBoxModelSerializer):
|
||||
|
||||
|
||||
class ServiceSerializer(NetBoxModelSerializer):
|
||||
device = serializers.SerializerMethodField(read_only=True)
|
||||
virtual_machine = serializers.SerializerMethodField(read_only=True)
|
||||
fhrp_group = serializers.SerializerMethodField(read_only=True)
|
||||
protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
|
||||
ipaddresses = SerializedPKRelatedField(
|
||||
queryset=IPAddress.objects.all(),
|
||||
@ -40,11 +37,15 @@ class ServiceSerializer(NetBoxModelSerializer):
|
||||
required=False,
|
||||
many=True
|
||||
)
|
||||
parent_object_type = ContentTypeField(
|
||||
queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS)
|
||||
)
|
||||
parent = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = [
|
||||
'id', 'url', 'display_url', 'display', 'device', 'virtual_machine', 'fhrp_group', 'name',
|
||||
'id', 'url', 'display_url', 'display', 'parent_object_type', 'parent_object_id', 'parent', 'name',
|
||||
'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', 'custom_fields',
|
||||
'created', 'last_updated',
|
||||
]
|
||||
@ -57,21 +58,3 @@ class ServiceSerializer(NetBoxModelSerializer):
|
||||
serializer = get_serializer_for_model(obj.parent)
|
||||
context = {'request': self.context['request']}
|
||||
return serializer(obj.parent, nested=True, context=context).data
|
||||
|
||||
@extend_schema_field(serializers.JSONField(allow_null=True))
|
||||
def get_device(self, obj):
|
||||
if isinstance(obj.parent, Device):
|
||||
return self.get_parent(obj)
|
||||
return None
|
||||
|
||||
@extend_schema_field(serializers.JSONField(allow_null=True))
|
||||
def get_virtual_machine(self, obj):
|
||||
if isinstance(obj.parent, VirtualMachine):
|
||||
return self.get_parent(obj)
|
||||
return None
|
||||
|
||||
@extend_schema_field(serializers.JSONField(allow_null=True))
|
||||
def get_fhrp_group(self, obj):
|
||||
if isinstance(obj.parent, FHRPGroup):
|
||||
return self.get_parent(obj)
|
||||
return None
|
||||
|
@ -1171,12 +1171,12 @@ class ServiceFilterSet(NetBoxModelFilterSet):
|
||||
field_name='pk',
|
||||
label=_('Virtual machine (ID)'),
|
||||
)
|
||||
fhrp_group = MultiValueCharFilter(
|
||||
fhrpgroup = MultiValueCharFilter(
|
||||
method='filter_fhrp_group',
|
||||
field_name='name',
|
||||
label=_('FHRP Group (name)'),
|
||||
)
|
||||
fhrp_group_id = MultiValueNumberFilter(
|
||||
fhrpgroup_id = MultiValueNumberFilter(
|
||||
method='filter_fhrp_group',
|
||||
field_name='pk',
|
||||
label=_('FHRP Group (ID)'),
|
||||
@ -1199,7 +1199,7 @@ class ServiceFilterSet(NetBoxModelFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = ('id', 'name', 'protocol', 'description')
|
||||
fields = ('id', 'name', 'protocol', 'description', 'parent_object_type', 'parent_object_id')
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
|
@ -19,8 +19,7 @@ from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
|
||||
if TYPE_CHECKING:
|
||||
from netbox.graphql.filter_lookups import IntegerArrayLookup, IntegerLookup
|
||||
from core.graphql.filters import ContentTypeFilter
|
||||
from dcim.graphql.filters import DeviceFilter, SiteFilter
|
||||
from virtualization.graphql.filters import VirtualMachineFilter
|
||||
from dcim.graphql.filters import SiteFilter
|
||||
from vpn.graphql.filters import L2VPNFilter
|
||||
from .enums import *
|
||||
|
||||
@ -216,16 +215,14 @@ class RouteTargetFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
|
||||
|
||||
@strawberry_django.filter(models.Service, lookups=True)
|
||||
class ServiceFilter(ContactFilterMixin, ServiceBaseFilterMixin, PrimaryModelFilterMixin):
|
||||
device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
|
||||
device_id: ID | None = strawberry_django.filter_field()
|
||||
virtual_machine: Annotated['VirtualMachineFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
|
||||
strawberry_django.filter_field()
|
||||
)
|
||||
virtual_machine_id: ID | None = strawberry_django.filter_field()
|
||||
name: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||
ipaddresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
|
||||
strawberry_django.filter_field()
|
||||
)
|
||||
parent_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
|
||||
strawberry_django.filter_field()
|
||||
)
|
||||
parent_object_id: ID | None = strawberry_django.filter_field()
|
||||
|
||||
|
||||
@strawberry_django.filter(models.ServiceTemplate, lookups=True)
|
||||
|
@ -5,12 +5,10 @@ import strawberry_django
|
||||
|
||||
from circuits.graphql.types import ProviderType
|
||||
from dcim.graphql.types import SiteType
|
||||
from dcim.models import Device
|
||||
from extras.graphql.mixins import ContactsMixin
|
||||
from ipam import models
|
||||
from netbox.graphql.scalars import BigInt
|
||||
from netbox.graphql.types import BaseObjectType, NetBoxObjectType, OrganizationalObjectType
|
||||
from virtualization.models import VirtualMachine
|
||||
from .filters import *
|
||||
from .mixins import IPAddressesMixin
|
||||
|
||||
@ -243,41 +241,14 @@ class RouteTargetType(NetBoxObjectType):
|
||||
|
||||
@strawberry_django.type(
|
||||
models.Service,
|
||||
fields='__all__',
|
||||
exclude=('parent_object_type', 'parent_object_id'),
|
||||
filters=ServiceFilter,
|
||||
pagination=True
|
||||
)
|
||||
class ServiceType(NetBoxObjectType, ContactsMixin):
|
||||
ports: List[int]
|
||||
# device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None
|
||||
# virtual_machine: Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')] | None
|
||||
# fhrp_group: Annotated["FHRPGroupType", strawberry.lazy('ipam.graphql.types')] | None
|
||||
ipaddresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]]
|
||||
|
||||
@strawberry_django.field
|
||||
def device(self) -> Annotated[Union[
|
||||
Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')],
|
||||
], strawberry.union("ServiceAssignmentType")] | None:
|
||||
if isinstance(self.parent, Device):
|
||||
return self.parent
|
||||
return None
|
||||
|
||||
@strawberry_django.field
|
||||
def virtual_machine(self) -> Annotated[Union[
|
||||
Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')],
|
||||
], strawberry.union("ServiceAssignmentType")] | None:
|
||||
if isinstance(self.parent, VirtualMachine):
|
||||
return self.parent
|
||||
return None
|
||||
|
||||
@strawberry_django.field
|
||||
def fhrp_group(self) -> Annotated[Union[
|
||||
Annotated["FHRPGroupType", strawberry.lazy('ipam.graphql.types')],
|
||||
], strawberry.union("ServiceAssignmentType")] | None:
|
||||
if isinstance(self.parent, models.FHRPGroup):
|
||||
return self.parent
|
||||
return None
|
||||
|
||||
@strawberry_django.field
|
||||
def parent(self) -> Annotated[Union[
|
||||
Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')],
|
||||
|
@ -123,7 +123,7 @@ class ServiceIndex(SearchIndex):
|
||||
('description', 500),
|
||||
('comments', 5000),
|
||||
)
|
||||
display_attrs = ('device', 'virtual_machine', 'description')
|
||||
display_attrs = ('parent', 'description')
|
||||
|
||||
|
||||
@register_search
|
||||
|
@ -1198,27 +1198,30 @@ class ServiceTest(APIViewTestCases.APIViewTestCase):
|
||||
Device.objects.bulk_create(devices)
|
||||
|
||||
services = (
|
||||
Service(device=devices[0], name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1]),
|
||||
Service(device=devices[0], name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[2]),
|
||||
Service(device=devices[0], name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[3]),
|
||||
Service(parent=devices[0], name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1]),
|
||||
Service(parent=devices[0], name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[2]),
|
||||
Service(parent=devices[0], name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[3]),
|
||||
)
|
||||
Service.objects.bulk_create(services)
|
||||
|
||||
cls.create_data = [
|
||||
{
|
||||
'device': devices[1].pk,
|
||||
'parent_object_id': devices[1].pk,
|
||||
'parent_object_type': 'dcim.device',
|
||||
'name': 'Service 4',
|
||||
'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
'ports': [4],
|
||||
},
|
||||
{
|
||||
'device': devices[1].pk,
|
||||
'parent_object_id': devices[1].pk,
|
||||
'parent_object_type': 'dcim.device',
|
||||
'name': 'Service 5',
|
||||
'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
'ports': [5],
|
||||
},
|
||||
{
|
||||
'device': devices[1].pk,
|
||||
'parent_object_id': devices[1].pk,
|
||||
'parent_object_type': 'dcim.device',
|
||||
'name': 'Service 6',
|
||||
'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
'ports': [6],
|
||||
|
@ -2332,34 +2332,39 @@ class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
|
||||
services = (
|
||||
Service(
|
||||
device=devices[0],
|
||||
parent=devices[0],
|
||||
name='Service 1',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
ports=[1001],
|
||||
description='foobar1',
|
||||
),
|
||||
Service(
|
||||
device=devices[1],
|
||||
parent=devices[1],
|
||||
name='Service 2',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
ports=[1002],
|
||||
description='foobar2',
|
||||
),
|
||||
Service(device=devices[2], name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_UDP, ports=[1003]),
|
||||
Service(
|
||||
virtual_machine=virtual_machines[0],
|
||||
parent=devices[2],
|
||||
name='Service 3',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_UDP,
|
||||
ports=[1003]
|
||||
),
|
||||
Service(
|
||||
parent=virtual_machines[0],
|
||||
name='Service 4',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
ports=[2001],
|
||||
),
|
||||
Service(
|
||||
virtual_machine=virtual_machines[1],
|
||||
parent=virtual_machines[1],
|
||||
name='Service 5',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
ports=[2002],
|
||||
),
|
||||
Service(
|
||||
virtual_machine=virtual_machines[2],
|
||||
parent=virtual_machines[2],
|
||||
name='Service 6',
|
||||
protocol=ServiceProtocolChoices.PROTOCOL_UDP,
|
||||
ports=[2003],
|
||||
|
@ -1053,6 +1053,8 @@ class ServiceTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
|
||||
class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
model = Service
|
||||
# TODO, related to #9816, cannot validate GFK
|
||||
validation_excluded_fields = ('device',)
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
@ -1081,7 +1083,6 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
|
||||
cls.form_data = {
|
||||
'device': device.pk,
|
||||
'virtual_machine': None,
|
||||
'name': 'Service X',
|
||||
'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
|
||||
'ports': '104,105',
|
||||
@ -1125,7 +1126,7 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
request = {
|
||||
'path': self._get_url('add'),
|
||||
'data': {
|
||||
'parent': device.pk,
|
||||
'device': device.pk,
|
||||
'service_template': service_template.pk,
|
||||
},
|
||||
}
|
||||
|
@ -1445,7 +1445,7 @@ class ServiceBulkImportView(generic.BulkImportView):
|
||||
|
||||
@register_model_view(Service, 'bulk_edit', path='edit', detail=False)
|
||||
class ServiceBulkEditView(generic.BulkEditView):
|
||||
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
|
||||
queryset = Service.objects.prefetch_related('parent')
|
||||
filterset = filtersets.ServiceFilterSet
|
||||
table = tables.ServiceTable
|
||||
form = forms.ServiceBulkEditForm
|
||||
@ -1453,6 +1453,6 @@ class ServiceBulkEditView(generic.BulkEditView):
|
||||
|
||||
@register_model_view(Service, 'bulk_delete', path='delete', detail=False)
|
||||
class ServiceBulkDeleteView(generic.BulkDeleteView):
|
||||
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
|
||||
queryset = Service.objects.prefetch_related('parent')
|
||||
filterset = filtersets.ServiceFilterSet
|
||||
table = tables.ServiceTable
|
||||
|
@ -130,7 +130,7 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co
|
||||
to='ipam.Service',
|
||||
content_type_field='parent_object_type',
|
||||
object_id_field='parent_object_id',
|
||||
related_query_name='virtualmachines',
|
||||
related_query_name='virtual_machine',
|
||||
)
|
||||
|
||||
# Counter fields
|
||||
|
Loading…
Reference in New Issue
Block a user