netbox-plugin-dns 1.0.7__py3-none-any.whl → 1.1.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of netbox-plugin-dns might be problematic. Click here for more details.

Files changed (69) hide show
  1. netbox_dns/__init__.py +21 -5
  2. netbox_dns/api/nested_serializers.py +16 -17
  3. netbox_dns/api/serializers.py +1 -0
  4. netbox_dns/api/serializers_/prefix.py +18 -0
  5. netbox_dns/api/serializers_/record.py +0 -1
  6. netbox_dns/api/serializers_/view.py +34 -2
  7. netbox_dns/api/urls.py +3 -0
  8. netbox_dns/api/views.py +36 -0
  9. netbox_dns/fields/__init__.py +1 -0
  10. netbox_dns/fields/ipam.py +18 -0
  11. netbox_dns/filtersets/record.py +1 -1
  12. netbox_dns/filtersets/view.py +16 -0
  13. netbox_dns/forms/view.py +116 -4
  14. netbox_dns/forms/zone.py +0 -8
  15. netbox_dns/graphql/schema.py +40 -16
  16. netbox_dns/graphql/types.py +1 -0
  17. netbox_dns/management/commands/setup_autodns.py +120 -0
  18. netbox_dns/migrations/0007_view_prefixes.py +18 -0
  19. netbox_dns/models/__init__.py +0 -2
  20. netbox_dns/models/contact.py +3 -9
  21. netbox_dns/models/nameserver.py +3 -8
  22. netbox_dns/models/record.py +71 -17
  23. netbox_dns/models/record_template.py +1 -4
  24. netbox_dns/models/registrar.py +1 -7
  25. netbox_dns/models/view.py +7 -9
  26. netbox_dns/models/zone.py +28 -29
  27. netbox_dns/models/zone_template.py +5 -8
  28. netbox_dns/signals/ipam_autodns.py +138 -0
  29. netbox_dns/tables/contact.py +1 -0
  30. netbox_dns/tables/nameserver.py +7 -1
  31. netbox_dns/tables/record.py +30 -10
  32. netbox_dns/tables/record_template.py +17 -0
  33. netbox_dns/tables/registrar.py +2 -0
  34. netbox_dns/tables/view.py +32 -3
  35. netbox_dns/tables/zone.py +15 -0
  36. netbox_dns/tables/zone_template.py +16 -2
  37. netbox_dns/template_content.py +28 -39
  38. netbox_dns/templates/netbox_dns/record.html +6 -6
  39. netbox_dns/templates/netbox_dns/view/related.html +17 -0
  40. netbox_dns/templates/netbox_dns/view.html +29 -0
  41. netbox_dns/urls/contact.py +32 -10
  42. netbox_dns/urls/nameserver.py +38 -14
  43. netbox_dns/urls/record.py +19 -7
  44. netbox_dns/urls/record_template.py +27 -18
  45. netbox_dns/urls/registrar.py +35 -11
  46. netbox_dns/urls/view.py +22 -8
  47. netbox_dns/urls/zone.py +46 -8
  48. netbox_dns/urls/zone_template.py +26 -16
  49. netbox_dns/utilities/__init__.py +2 -74
  50. netbox_dns/utilities/conversions.py +83 -0
  51. netbox_dns/utilities/ipam_autodns.py +205 -0
  52. netbox_dns/validators/dns_name.py +0 -9
  53. netbox_dns/views/contact.py +1 -0
  54. netbox_dns/views/nameserver.py +3 -7
  55. netbox_dns/views/record.py +2 -9
  56. netbox_dns/views/record_template.py +1 -1
  57. netbox_dns/views/registrar.py +1 -0
  58. netbox_dns/views/view.py +1 -6
  59. netbox_dns/views/zone.py +6 -7
  60. netbox_dns/views/zone_template.py +2 -2
  61. {netbox_plugin_dns-1.0.7.dist-info → netbox_plugin_dns-1.1.0b1.dist-info}/METADATA +2 -2
  62. {netbox_plugin_dns-1.0.7.dist-info → netbox_plugin_dns-1.1.0b1.dist-info}/RECORD +64 -61
  63. netbox_dns/management/commands/setup_coupling.py +0 -109
  64. netbox_dns/migrations/0007_alter_ordering_options.py +0 -25
  65. netbox_dns/signals/ipam_coupling.py +0 -168
  66. netbox_dns/templates/netbox_dns/related_dns_objects.html +0 -21
  67. netbox_dns/utilities/ipam_coupling.py +0 -112
  68. {netbox_plugin_dns-1.0.7.dist-info → netbox_plugin_dns-1.1.0b1.dist-info}/LICENSE +0 -0
  69. {netbox_plugin_dns-1.0.7.dist-info → netbox_plugin_dns-1.1.0b1.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py CHANGED
@@ -1,13 +1,18 @@
1
+ from django.conf import settings
2
+
1
3
  from netbox.plugins import PluginConfig
4
+ from ipam.choices import IPAddressStatusChoices
5
+
6
+ from netbox_dns.choices import RecordTypeChoices
2
7
 
3
- __version__ = "1.0.7"
8
+ __version__ = "1.1.0-beta1"
4
9
 
5
10
 
6
11
  class DNSConfig(PluginConfig):
7
12
  name = "netbox_dns"
8
13
  verbose_name = "NetBox DNS"
9
14
  description = "NetBox plugin for DNS data"
10
- min_version = "4.0.0"
15
+ min_version = "4.1.0-beta1"
11
16
  version = __version__
12
17
  author = "Peter Eckel"
13
18
  author_email = "pete@netbox-dns.org"
@@ -20,13 +25,18 @@ class DNSConfig(PluginConfig):
20
25
  "zone_soa_retry": 7200,
21
26
  "zone_soa_expire": 2419200,
22
27
  "zone_soa_minimum": 3600,
23
- "feature_ipam_coupling": False,
28
+ "autodns_disabled": False,
29
+ "autodns_ipaddress_active_status": [
30
+ IPAddressStatusChoices.STATUS_ACTIVE,
31
+ IPAddressStatusChoices.STATUS_DHCP,
32
+ IPAddressStatusChoices.STATUS_SLAAC,
33
+ ],
24
34
  "tolerate_characters_in_zone_labels": "",
25
35
  "tolerate_underscores_in_labels": False,
26
36
  "tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
27
37
  "tolerate_leading_underscore_types": [
28
- "TXT",
29
- "SRV",
38
+ RecordTypeChoices.TXT,
39
+ RecordTypeChoices.SRV,
30
40
  ],
31
41
  "tolerate_non_rfc1035_types": [],
32
42
  "enable_root_zones": False,
@@ -37,6 +47,12 @@ class DNSConfig(PluginConfig):
37
47
  }
38
48
  base_url = "netbox-dns"
39
49
 
50
+ def ready(self):
51
+ super().ready()
52
+
53
+ if not settings.PLUGINS_CONFIG["netbox_dns"].get("autodns_disabled"):
54
+ from netbox_dns.signals import ipam_autodns
55
+
40
56
 
41
57
  #
42
58
  # Initialize plugin config
@@ -59,22 +59,6 @@ class NestedZoneSerializer(WritableNestedSerializer):
59
59
  ]
60
60
 
61
61
 
62
- class NestedZoneTemplateSerializer(WritableNestedSerializer):
63
- url = serializers.HyperlinkedIdentityField(
64
- view_name="plugins-api:netbox_dns-api:zonetemplate-detail"
65
- )
66
-
67
- class Meta:
68
- model = ZoneTemplate
69
- fields = (
70
- "id",
71
- "url",
72
- "name",
73
- "display",
74
- "description",
75
- )
76
-
77
-
78
62
  class NestedRecordSerializer(WritableNestedSerializer):
79
63
  url = serializers.HyperlinkedIdentityField(
80
64
  view_name="plugins-api:netbox_dns-api:record-detail"
@@ -102,7 +86,6 @@ class NestedRecordSerializer(WritableNestedSerializer):
102
86
  "status",
103
87
  "ttl",
104
88
  "zone",
105
- "managed",
106
89
  "active",
107
90
  ]
108
91
 
@@ -126,3 +109,19 @@ class NestedRecordTemplateSerializer(WritableNestedSerializer):
126
109
  "ttl",
127
110
  "description",
128
111
  )
112
+
113
+
114
+ class NestedZoneTemplateSerializer(WritableNestedSerializer):
115
+ url = serializers.HyperlinkedIdentityField(
116
+ view_name="plugins-api:netbox_dns-api:zonetemplate-detail"
117
+ )
118
+
119
+ class Meta:
120
+ model = ZoneTemplate
121
+ fields = (
122
+ "id",
123
+ "url",
124
+ "name",
125
+ "display",
126
+ "description",
127
+ )
@@ -6,5 +6,6 @@ from .serializers_.view import *
6
6
  from .serializers_.zone import *
7
7
  from .serializers_.zone_template import *
8
8
  from .serializers_.record_template import *
9
+ from .serializers_.prefix import *
9
10
 
10
11
  from .nested_serializers import *
@@ -0,0 +1,18 @@
1
+ from rest_framework.serializers import HyperlinkedIdentityField
2
+
3
+ from ipam.api.serializers import PrefixSerializer as IPAMPrefixSerializer
4
+
5
+
6
+ __all__ = ("PrefixSerializer",)
7
+
8
+
9
+ class PrefixSerializer(IPAMPrefixSerializer):
10
+ url = HyperlinkedIdentityField(view_name="plugins-api:netbox_dns-api:prefix-detail")
11
+
12
+ def to_representation(self, instance):
13
+ representation = super().to_representation(instance)
14
+
15
+ if instance.vrf is not None:
16
+ representation["display"] += f" [{instance.vrf.name}]"
17
+
18
+ return representation
@@ -87,6 +87,5 @@ class RecordSerializer(NetBoxModelSerializer):
87
87
  "status",
88
88
  "ttl",
89
89
  "description",
90
- "managed",
91
90
  "active",
92
91
  )
@@ -1,7 +1,8 @@
1
1
  from rest_framework import serializers
2
2
 
3
3
  from netbox.api.serializers import NetBoxModelSerializer
4
- from tenancy.api.serializers_.tenants import TenantSerializer
4
+ from tenancy.api.serializers import TenantSerializer
5
+ from ipam.api.serializers import PrefixSerializer
5
6
 
6
7
  from netbox_dns.models import View
7
8
 
@@ -16,8 +17,38 @@ class ViewSerializer(NetBoxModelSerializer):
16
17
  default_view = serializers.BooleanField(
17
18
  read_only=True,
18
19
  )
20
+ prefixes = PrefixSerializer(
21
+ many=True,
22
+ nested=True,
23
+ read_only=False,
24
+ required=False,
25
+ help_text="IPAM Prefixes assigned to the View",
26
+ )
27
+ tenant = TenantSerializer(
28
+ nested=True,
29
+ required=False,
30
+ allow_null=True,
31
+ )
32
+
33
+ def create(self, validated_data):
34
+ prefixes = validated_data.pop("prefixes", None)
35
+
36
+ view = super().create(validated_data)
37
+
38
+ if prefixes is not None:
39
+ view.prefixes.set(prefixes)
40
+
41
+ return view
42
+
43
+ def update(self, instance, validated_data):
44
+ prefixes = validated_data.pop("prefixes", None)
45
+
46
+ view = super().update(instance, validated_data)
47
+
48
+ if prefixes is not None:
49
+ view.prefixes.set(prefixes)
19
50
 
20
- tenant = TenantSerializer(nested=True, required=False, allow_null=True)
51
+ return view
21
52
 
22
53
  class Meta:
23
54
  model = View
@@ -33,5 +64,6 @@ class ViewSerializer(NetBoxModelSerializer):
33
64
  "last_updated",
34
65
  "custom_fields",
35
66
  "tenant",
67
+ "prefixes",
36
68
  )
37
69
  brief_fields = ("id", "url", "display", "name", "default_view", "description")
netbox_dns/api/urls.py CHANGED
@@ -10,6 +10,7 @@ from netbox_dns.api.views import (
10
10
  ContactViewSet,
11
11
  ZoneTemplateViewSet,
12
12
  RecordTemplateViewSet,
13
+ PrefixViewSet,
13
14
  )
14
15
 
15
16
  router = NetBoxRouter()
@@ -24,4 +25,6 @@ router.register("contacts", ContactViewSet)
24
25
  router.register("zonetemplates", ZoneTemplateViewSet)
25
26
  router.register("recordtemplates", RecordTemplateViewSet)
26
27
 
28
+ router.register("prefixes", PrefixViewSet)
29
+
27
30
  urlpatterns = router.urls
netbox_dns/api/views.py CHANGED
@@ -1,6 +1,10 @@
1
1
  from rest_framework import serializers
2
+ from rest_framework.decorators import action
3
+ from rest_framework.response import Response
2
4
  from rest_framework.routers import APIRootView
3
5
 
6
+ from ipam.models import Prefix
7
+
4
8
  from netbox.api.viewsets import NetBoxModelViewSet
5
9
 
6
10
  from netbox_dns.api.serializers import (
@@ -12,6 +16,7 @@ from netbox_dns.api.serializers import (
12
16
  ContactSerializer,
13
17
  ZoneTemplateSerializer,
14
18
  RecordTemplateSerializer,
19
+ PrefixSerializer,
15
20
  )
16
21
  from netbox_dns.filtersets import (
17
22
  ViewFilterSet,
@@ -45,6 +50,12 @@ class ViewViewSet(NetBoxModelViewSet):
45
50
  serializer_class = ViewSerializer
46
51
  filterset_class = ViewFilterSet
47
52
 
53
+ @action(detail=True, methods=["get"])
54
+ def views(self, request, pk=None):
55
+ views = View.objects.filter(zone=pk)
56
+ serializer = ViewSerializer(views, many=True, context={"request": request})
57
+ return Response(serializer.data)
58
+
48
59
 
49
60
  class ZoneViewSet(NetBoxModelViewSet):
50
61
  queryset = Zone.objects.prefetch_related(
@@ -58,12 +69,32 @@ class ZoneViewSet(NetBoxModelViewSet):
58
69
  serializer_class = ZoneSerializer
59
70
  filterset_class = ZoneFilterSet
60
71
 
72
+ @action(detail=True, methods=["get"])
73
+ def records(self, request, pk=None):
74
+ records = Record.objects.filter(zone=pk)
75
+ serializer = RecordSerializer(records, many=True, context={"request": request})
76
+ return Response(serializer.data)
77
+
78
+ @action(detail=True, methods=["get"])
79
+ def nameservers(self, request, pk=None):
80
+ nameservers = NameServer.objects.filter(zones__id=pk)
81
+ serializer = NameServerSerializer(
82
+ nameservers, many=True, context={"request": request}
83
+ )
84
+ return Response(serializer.data)
85
+
61
86
 
62
87
  class NameServerViewSet(NetBoxModelViewSet):
63
88
  queryset = NameServer.objects.prefetch_related("zones", "tenant")
64
89
  serializer_class = NameServerSerializer
65
90
  filterset_class = NameServerFilterSet
66
91
 
92
+ @action(detail=True, methods=["get"])
93
+ def zones(self, request, pk=None):
94
+ zones = Zone.objects.filter(nameservers__id=pk)
95
+ serializer = ZoneSerializer(zones, many=True, context={"request": request})
96
+ return Response(serializer.data)
97
+
67
98
 
68
99
  class RecordViewSet(NetBoxModelViewSet):
69
100
  queryset = Record.objects.all().prefetch_related("zone", "zone__view", "tenant")
@@ -124,3 +155,8 @@ class RecordTemplateViewSet(NetBoxModelViewSet):
124
155
  queryset = RecordTemplate.objects.all()
125
156
  serializer_class = RecordTemplateSerializer
126
157
  filterset_class = RecordTemplateFilterSet
158
+
159
+
160
+ class PrefixViewSet(NetBoxModelViewSet):
161
+ queryset = Prefix.objects.all()
162
+ serializer_class = PrefixSerializer
@@ -1,3 +1,4 @@
1
1
  from .network import *
2
2
  from .address import *
3
3
  from .rfc2317 import *
4
+ from .ipam import *
@@ -0,0 +1,18 @@
1
+ from utilities.forms.fields import DynamicModelMultipleChoiceField
2
+ from utilities.forms.widgets import APISelectMultiple
3
+
4
+
5
+ __all__ = ("PrefixDynamicModelMultipleChoiceField",)
6
+
7
+
8
+ class PrefixDynamicModelMultipleChoiceField(DynamicModelMultipleChoiceField):
9
+ def __init__(self, *args, **kwargs):
10
+ super().__init__(*args, **kwargs)
11
+
12
+ widget = APISelectMultiple(api_url="/api/plugins/netbox-dns/prefixes")
13
+
14
+ def label_from_instance(self, obj):
15
+ if obj.vrf:
16
+ return f"{str(obj.prefix)} [{obj.vrf.name}]"
17
+
18
+ return str(obj.prefix)
@@ -121,7 +121,7 @@ class RecordFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
121
121
  if not value.strip():
122
122
  return queryset
123
123
  qs_filter = (
124
- Q(fqdn__icontains=value)
124
+ Q(name__icontains=value)
125
125
  | Q(value__icontains=value)
126
126
  | Q(zone__name__icontains=value)
127
127
  )
@@ -1,7 +1,10 @@
1
+ import django_filters
2
+
1
3
  from django.db.models import Q
2
4
 
3
5
  from netbox.filtersets import NetBoxModelFilterSet
4
6
  from tenancy.filtersets import TenancyFilterSet
7
+ from ipam.models import Prefix
5
8
 
6
9
  from netbox_dns.models import View
7
10
 
@@ -10,6 +13,19 @@ __all__ = ("ViewFilterSet",)
10
13
 
11
14
 
12
15
  class ViewFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
16
+ prefix_id = django_filters.ModelMultipleChoiceFilter(
17
+ queryset=Prefix.objects.all(),
18
+ field_name="prefixes",
19
+ to_field_name="id",
20
+ label="Prefixes ID",
21
+ )
22
+ prefix = django_filters.ModelMultipleChoiceFilter(
23
+ queryset=Prefix.objects.all(),
24
+ field_name="prefixes__prefix",
25
+ to_field_name="prefix",
26
+ label="Prefix",
27
+ )
28
+
13
29
  class Meta:
14
30
  model = View
15
31
  fields = ("id", "name", "default_view", "description")
netbox_dns/forms/view.py CHANGED
@@ -1,4 +1,7 @@
1
1
  from django import forms
2
+ from django.conf import settings
3
+ from django.core.exceptions import ValidationError
4
+ from django.db.models import Q, Count
2
5
 
3
6
  from netbox.forms import (
4
7
  NetBoxModelBulkEditForm,
@@ -9,14 +12,23 @@ from netbox.forms import (
9
12
  from utilities.forms.fields import (
10
13
  TagFilterField,
11
14
  CSVModelChoiceField,
15
+ CSVModelMultipleChoiceField,
12
16
  DynamicModelChoiceField,
17
+ DynamicModelMultipleChoiceField,
13
18
  )
14
19
  from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES
15
20
  from utilities.forms.rendering import FieldSet
16
21
  from tenancy.models import Tenant
17
22
  from tenancy.forms import TenancyForm, TenancyFilterForm
23
+ from ipam.models import Prefix
18
24
 
19
25
  from netbox_dns.models import View
26
+ from netbox_dns.fields import PrefixDynamicModelMultipleChoiceField
27
+ from netbox_dns.utilities import (
28
+ get_ip_addresses_by_prefix,
29
+ update_dns_records,
30
+ get_views_by_prefix,
31
+ )
20
32
 
21
33
 
22
34
  __all__ = (
@@ -27,22 +39,102 @@ __all__ = (
27
39
  )
28
40
 
29
41
 
30
- class ViewForm(TenancyForm, NetBoxModelForm):
42
+ class ViewPrefixUpdateMixin:
43
+ def clean(self, *args, **kwargs):
44
+ super().clean(*args, **kwargs)
45
+
46
+ if self.instance.pk is None or "prefixes" not in self.changed_data:
47
+ return
48
+
49
+ prefixes = self.cleaned_data.get("prefixes")
50
+ old_prefixes = View.objects.get(pk=self.instance.pk).prefixes.all()
51
+
52
+ for prefix in prefixes.difference(old_prefixes):
53
+ for ip_address in get_ip_addresses_by_prefix(prefix, check_view=False):
54
+ try:
55
+ update_dns_records(ip_address, commit=False, view=self.instance)
56
+ except ValidationError as exc:
57
+ self.add_error("prefixes", exc.messages)
58
+
59
+ # +
60
+ # Determine the prefixes that, when removed from the view, have no direct view
61
+ # assignment left. These prefixes will potentially inherit from a different view,
62
+ # which means that they have to be validated against different zones.
63
+ # -
64
+ check_prefixes = set(
65
+ old_prefixes.annotate(view_count=Count("netbox_dns_views")).filter(
66
+ Q(view_count=1, netbox_dns_views=self.instance)
67
+ | Q(netbox_dns_views__isnull=True)
68
+ )
69
+ ) - set(prefixes)
70
+
71
+ for check_prefix in check_prefixes:
72
+ # +
73
+ # Check whether the prefix will get a new view by inheritance from its
74
+ # parent. If that's the case, the IP addresses need to be checked.
75
+ # -
76
+ if (parent := check_prefix.get_parents().last()) is None:
77
+ return
78
+
79
+ for view in get_views_by_prefix(parent):
80
+ if view == self.instance:
81
+ continue
82
+
83
+ for ip_address in get_ip_addresses_by_prefix(
84
+ check_prefix, check_view=False
85
+ ):
86
+ try:
87
+ update_dns_records(ip_address, commit=False, view=view)
88
+ except ValidationError as exc:
89
+ self.add_error("prefixes", exc.messages)
90
+
91
+
92
+ class ViewForm(ViewPrefixUpdateMixin, TenancyForm, NetBoxModelForm):
93
+ def __init__(self, *args, **kwargs):
94
+ super().__init__(*args, **kwargs)
95
+
96
+ if settings.PLUGINS_CONFIG["netbox_dns"].get("autodns_disabled"):
97
+ del self.fields["prefixes"]
98
+
99
+ prefixes = PrefixDynamicModelMultipleChoiceField(
100
+ queryset=Prefix.objects.all(),
101
+ required=False,
102
+ label="IPAM Prefixes",
103
+ context={
104
+ "depth": None,
105
+ },
106
+ )
107
+
31
108
  fieldsets = (
32
109
  FieldSet("name", "default_view", "description", "tags", name="View"),
110
+ FieldSet("prefixes"),
33
111
  FieldSet("tenant_group", "tenant", name="Tenancy"),
34
112
  )
35
113
 
36
114
  class Meta:
37
115
  model = View
38
- fields = ("name", "default_view", "description", "tags", "tenant")
116
+ fields = (
117
+ "name",
118
+ "default_view",
119
+ "description",
120
+ "tags",
121
+ "tenant",
122
+ "prefixes",
123
+ )
39
124
 
40
125
 
41
126
  class ViewFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
127
+ def __init__(self, *args, **kwargs):
128
+ super().__init__(*args, **kwargs)
129
+
130
+ if settings.PLUGINS_CONFIG["netbox_dns"].get("autodns_disabled"):
131
+ del self.fields["prefix_id"]
132
+
42
133
  model = View
43
134
  fieldsets = (
44
135
  FieldSet("q", "filter_id", "tag"),
45
136
  FieldSet("name", "default_view", "description", name="Attributes"),
137
+ FieldSet("prefix_id"),
46
138
  FieldSet("tenant_group_id", "tenant_id", name="Tenancy"),
47
139
  )
48
140
 
@@ -56,10 +148,30 @@ class ViewFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
56
148
  description = forms.CharField(
57
149
  required=False,
58
150
  )
151
+ prefix_id = PrefixDynamicModelMultipleChoiceField(
152
+ queryset=Prefix.objects.all(),
153
+ required=False,
154
+ label="Prefix",
155
+ context={
156
+ "depth": None,
157
+ },
158
+ )
59
159
  tag = TagFilterField(View)
60
160
 
61
161
 
62
- class ViewImportForm(NetBoxModelImportForm):
162
+ class ViewImportForm(ViewPrefixUpdateMixin, NetBoxModelImportForm):
163
+ def __init__(self, *args, **kwargs):
164
+ super().__init__(*args, **kwargs)
165
+
166
+ if settings.PLUGINS_CONFIG["netbox_dns"].get("autodns_disabled"):
167
+ del self.fields["prefixes"]
168
+
169
+ prefixes = CSVModelMultipleChoiceField(
170
+ queryset=Prefix.objects.all(),
171
+ to_field_name="id",
172
+ required=False,
173
+ help_text="Prefix IDs assigned to the view",
174
+ )
63
175
  tenant = CSVModelChoiceField(
64
176
  queryset=Tenant.objects.all(),
65
177
  to_field_name="name",
@@ -69,7 +181,7 @@ class ViewImportForm(NetBoxModelImportForm):
69
181
 
70
182
  class Meta:
71
183
  model = View
72
- fields = ("name", "description", "tenant", "tags")
184
+ fields = ("name", "description", "prefixes", "tenant", "tags")
73
185
 
74
186
 
75
187
  class ViewBulkEditForm(NetBoxModelBulkEditForm):
netbox_dns/forms/zone.py CHANGED
@@ -81,14 +81,6 @@ class ZoneTemplateUpdateMixin:
81
81
  else:
82
82
  zone_data = self.cleaned_data.copy()
83
83
 
84
- custom_fields = dict()
85
- for key, value in zone_data.copy().items():
86
- if key.startswith("cf_"):
87
- custom_fields[key[3:]] = value
88
- zone_data.pop(key)
89
- if custom_fields:
90
- zone_data["custom_field_data"] = custom_fields
91
-
92
84
  zone_data.pop("template", None)
93
85
  zone_data.pop("tenant_group", None)
94
86
  zone_data.pop("_init_time", None)
@@ -25,55 +25,79 @@ from .types import (
25
25
  )
26
26
 
27
27
 
28
- @strawberry.type(name="Query")
28
+ @strawberry.type
29
29
  class NetBoxDNSNameServerQuery:
30
- netbox_dns_nameserver: NetBoxDNSNameServerType = strawberry_django.field()
30
+ @strawberry.field
31
+ def netbox_dns_nameserver(self, id: int) -> NetBoxDNSNameServerType:
32
+ return NameServer.objects.get(pk=id)
33
+
31
34
  netbox_dns_nameserver_list: List[NetBoxDNSNameServerType] = (
32
35
  strawberry_django.field()
33
36
  )
34
37
 
35
38
 
36
- @strawberry.type(name="Query")
39
+ @strawberry.type
37
40
  class NetBoxDNSViewQuery:
38
- netbox_dns_view: NetBoxDNSViewType = strawberry_django.field()
41
+ @strawberry.field
42
+ def netbox_dns_view(self, id: int) -> NetBoxDNSViewType:
43
+ return View.objects.get(pk=id)
44
+
39
45
  netbox_dns_view_list: List[NetBoxDNSViewType] = strawberry_django.field()
40
46
 
41
47
 
42
- @strawberry.type(name="Query")
48
+ @strawberry.type
43
49
  class NetBoxDNSZoneQuery:
44
- netbox_dns_zone: NetBoxDNSZoneType = strawberry_django.field()
50
+ @strawberry.field
51
+ def netbox_dns_zone(self, id: int) -> NetBoxDNSZoneType:
52
+ return Zone.objects.get(pk=id)
53
+
45
54
  netbox_dns_zone_list: List[NetBoxDNSZoneType] = strawberry_django.field()
46
55
 
47
56
 
48
- @strawberry.type(name="Query")
57
+ @strawberry.type
49
58
  class NetBoxDNSRecordQuery:
50
- netbox_dns_record: NetBoxDNSRecordType = strawberry_django.field()
59
+ @strawberry.field
60
+ def netbox_dns_record(self, id: int) -> NetBoxDNSRecordType:
61
+ return Record.objects.get(pk=id)
62
+
51
63
  netbox_dns_record_list: List[NetBoxDNSRecordType] = strawberry_django.field()
52
64
 
53
65
 
54
- @strawberry.type(name="Query")
66
+ @strawberry.type
55
67
  class NetBoxDNSContactQuery:
56
- netbox_dns_contact: NetBoxDNSContactType = strawberry_django.field()
68
+ @strawberry.field
69
+ def netbox_dns_contact(self, id: int) -> NetBoxDNSContactType:
70
+ return Contact.objects.get(pk=id)
71
+
57
72
  netbox_dns_contact_list: List[NetBoxDNSContactType] = strawberry_django.field()
58
73
 
59
74
 
60
- @strawberry.type(name="Query")
75
+ @strawberry.type
61
76
  class NetBoxDNSRegistrarQuery:
62
- netbox_dns_registrar: NetBoxDNSRegistrarType = strawberry_django.field()
77
+ @strawberry.field
78
+ def netbox_dns_registrar(self, id: int) -> NetBoxDNSRegistrarType:
79
+ return Registrar.objects.get(pk=id)
80
+
63
81
  netbox_dns_registrar_list: List[NetBoxDNSRegistrarType] = strawberry_django.field()
64
82
 
65
83
 
66
- @strawberry.type(name="Query")
84
+ @strawberry.type
67
85
  class NetBoxDNSZoneTemplateQuery:
68
- netbox_dns_zone_template: NetBoxDNSZoneTemplateType = strawberry_django.field()
86
+ @strawberry.field
87
+ def netbox_dns_zone_template(self, id: int) -> NetBoxDNSZoneTemplateType:
88
+ return ZoneTemplate.objects.get(pk=id)
89
+
69
90
  netbox_dns_zone_template_list: List[NetBoxDNSZoneTemplateType] = (
70
91
  strawberry_django.field()
71
92
  )
72
93
 
73
94
 
74
- @strawberry.type(name="Query")
95
+ @strawberry.type
75
96
  class NetBoxDNSRecordTemplateQuery:
76
- netbox_dns_record_template: NetBoxDNSRecordTemplateType = strawberry_django.field()
97
+ @strawberry.field
98
+ def netbox_dns_record_template(self, id: int) -> NetBoxDNSRecordTemplateType:
99
+ return RecordTemplate.objects.get(pk=id)
100
+
77
101
  netbox_dns_record_template_list: List[NetBoxDNSRecordTemplateType] = (
78
102
  strawberry_django.field()
79
103
  )
@@ -40,6 +40,7 @@ class NetBoxDNSViewType(NetBoxObjectType):
40
40
  name: str
41
41
  description: str
42
42
  tenant: Annotated["TenantType", strawberry.lazy("tenancy.graphql.types")] | None
43
+ prefixes: List[Annotated["PrefixType", strawberry.lazy("ipam.graphql.types")]]
43
44
 
44
45
 
45
46
  @strawberry_django.type(Zone, fields="__all__", filters=NetBoxDNSZoneFilter)