netbox-plugin-dns 1.1.2__py3-none-any.whl → 1.1.4__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 (84) hide show
  1. netbox_dns/__init__.py +14 -6
  2. netbox_dns/api/nested_serializers.py +3 -2
  3. netbox_dns/api/serializers_/nameserver.py +2 -1
  4. netbox_dns/api/serializers_/record.py +5 -4
  5. netbox_dns/api/serializers_/record_template.py +2 -1
  6. netbox_dns/api/serializers_/view.py +2 -1
  7. netbox_dns/api/serializers_/zone.py +12 -11
  8. netbox_dns/api/serializers_/zone_template.py +8 -7
  9. netbox_dns/api/views.py +9 -4
  10. netbox_dns/choices/record.py +4 -2
  11. netbox_dns/choices/zone.py +8 -4
  12. netbox_dns/fields/address.py +5 -22
  13. netbox_dns/fields/network.py +2 -1
  14. netbox_dns/fields/rfc2317.py +7 -3
  15. netbox_dns/filtersets/nameserver.py +3 -2
  16. netbox_dns/filtersets/record.py +14 -9
  17. netbox_dns/filtersets/record_template.py +3 -2
  18. netbox_dns/filtersets/view.py +3 -2
  19. netbox_dns/filtersets/zone.py +24 -22
  20. netbox_dns/filtersets/zone_template.py +15 -14
  21. netbox_dns/forms/nameserver.py +41 -17
  22. netbox_dns/forms/record.py +61 -32
  23. netbox_dns/forms/record_template.py +49 -28
  24. netbox_dns/forms/registrar.py +21 -17
  25. netbox_dns/forms/registration_contact.py +37 -25
  26. netbox_dns/forms/view.py +49 -27
  27. netbox_dns/forms/zone.py +173 -120
  28. netbox_dns/forms/zone_template.py +53 -43
  29. netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  30. netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
  31. netbox_dns/management/commands/rebuild_dnssync.py +14 -1
  32. netbox_dns/models/nameserver.py +6 -2
  33. netbox_dns/models/record.py +74 -40
  34. netbox_dns/models/record_template.py +17 -9
  35. netbox_dns/models/registrar.py +11 -7
  36. netbox_dns/models/registration_contact.py +23 -11
  37. netbox_dns/models/view.py +15 -6
  38. netbox_dns/models/zone.py +83 -50
  39. netbox_dns/models/zone_template.py +12 -10
  40. netbox_dns/navigation.py +30 -28
  41. netbox_dns/signals/ipam_dnssync.py +21 -14
  42. netbox_dns/tables/ipam_dnssync.py +2 -1
  43. netbox_dns/tables/nameserver.py +2 -0
  44. netbox_dns/tables/record.py +21 -11
  45. netbox_dns/tables/record_template.py +12 -5
  46. netbox_dns/tables/registrar.py +2 -0
  47. netbox_dns/tables/registration_contact.py +2 -0
  48. netbox_dns/tables/view.py +3 -1
  49. netbox_dns/tables/zone.py +15 -2
  50. netbox_dns/tables/zone_template.py +7 -0
  51. netbox_dns/templates/netbox_dns/nameserver.html +6 -5
  52. netbox_dns/templates/netbox_dns/record/managed.html +2 -1
  53. netbox_dns/templates/netbox_dns/record/related.html +26 -14
  54. netbox_dns/templates/netbox_dns/record.html +39 -20
  55. netbox_dns/templates/netbox_dns/recordtemplate.html +27 -15
  56. netbox_dns/templates/netbox_dns/registrar.html +11 -10
  57. netbox_dns/templates/netbox_dns/registrationcontact.html +16 -15
  58. netbox_dns/templates/netbox_dns/view/button.html +2 -1
  59. netbox_dns/templates/netbox_dns/view/prefix.html +7 -4
  60. netbox_dns/templates/netbox_dns/view/related.html +26 -10
  61. netbox_dns/templates/netbox_dns/view.html +11 -14
  62. netbox_dns/templates/netbox_dns/zone/base.html +2 -1
  63. netbox_dns/templates/netbox_dns/zone/child.html +3 -2
  64. netbox_dns/templates/netbox_dns/zone/record.html +3 -2
  65. netbox_dns/templates/netbox_dns/zone/registration.html +8 -7
  66. netbox_dns/templates/netbox_dns/zone.html +28 -30
  67. netbox_dns/templates/netbox_dns/zonetemplate.html +27 -17
  68. netbox_dns/utilities/ipam_dnssync.py +15 -4
  69. netbox_dns/validators/dns_name.py +11 -4
  70. netbox_dns/validators/dns_value.py +55 -9
  71. netbox_dns/validators/rfc2317.py +6 -3
  72. netbox_dns/views/nameserver.py +4 -2
  73. netbox_dns/views/record_template.py +4 -3
  74. netbox_dns/views/registrar.py +3 -1
  75. netbox_dns/views/registration_contact.py +2 -1
  76. netbox_dns/views/view.py +2 -1
  77. netbox_dns/views/zone.py +6 -4
  78. netbox_dns/views/zone_template.py +8 -7
  79. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/METADATA +2 -2
  80. netbox_plugin_dns-1.1.4.dist-info/RECORD +150 -0
  81. netbox_plugin_dns-1.1.2.dist-info/RECORD +0 -148
  82. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/LICENSE +0 -0
  83. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/WHEEL +0 -0
  84. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  from django import forms
2
+ from django.utils.translation import gettext_lazy as _
2
3
 
3
4
  from netbox.forms import (
4
5
  NetBoxModelBulkEditForm,
@@ -14,7 +15,7 @@ from utilities.forms.fields import (
14
15
  DynamicModelChoiceField,
15
16
  )
16
17
  from utilities.forms.rendering import FieldSet
17
- from tenancy.models import Tenant
18
+ from tenancy.models import Tenant, TenantGroup
18
19
  from tenancy.forms import TenancyForm, TenancyFilterForm
19
20
 
20
21
  from netbox_dns.models import (
@@ -45,18 +46,18 @@ class ZoneTemplateForm(TenancyForm, NetBoxModelForm):
45
46
  )
46
47
 
47
48
  fieldsets = (
48
- FieldSet("name", "description", "nameservers", name="Zone Template"),
49
- FieldSet("record_templates", name="Record Templates"),
49
+ FieldSet("name", "description", "nameservers", name=_("Zone Template")),
50
+ FieldSet("record_templates", name=_("Record Templates")),
50
51
  FieldSet(
51
52
  "registrar",
52
53
  "registrant",
53
54
  "admin_c",
54
55
  "tech_c",
55
56
  "billing_c",
56
- name="Domain Registration",
57
+ name=_("Domain Registration"),
57
58
  ),
58
- FieldSet("tags", name="Tags"),
59
- FieldSet("tenant_group", "tenant", name="Tenancy"),
59
+ FieldSet("tenant_group", "tenant", name=_("Tenancy")),
60
+ FieldSet("tags", name=_("Tags")),
60
61
  )
61
62
 
62
63
  class Meta:
@@ -67,13 +68,14 @@ class ZoneTemplateForm(TenancyForm, NetBoxModelForm):
67
68
  "nameservers",
68
69
  "record_templates",
69
70
  "description",
70
- "tags",
71
71
  "registrar",
72
72
  "registrant",
73
73
  "admin_c",
74
74
  "tech_c",
75
75
  "billing_c",
76
+ "tenant_group",
76
77
  "tenant",
78
+ "tags",
77
79
  )
78
80
 
79
81
 
@@ -81,32 +83,32 @@ class ZoneTemplateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
81
83
  model = ZoneTemplate
82
84
  fieldsets = (
83
85
  FieldSet("q", "filter_id", "tag"),
84
- FieldSet("name", "nameserver_id", "description", name="Attributes"),
85
- FieldSet("record_template_id", name="Record Templates"),
86
+ FieldSet("name", "nameserver_id", "description", name=_("Attributes")),
87
+ FieldSet("record_template_id", name=_("Record Templates")),
86
88
  FieldSet(
87
89
  "registrar_id",
88
90
  "registrant_id",
89
91
  "admin_c_id",
90
92
  "tech_c_id",
91
93
  "billing_c_id",
92
- name="Registration",
94
+ name=_("Registration"),
93
95
  ),
94
- FieldSet("tenant_group_id", "tenant_id", name="Tenancy"),
96
+ FieldSet("tenant_group_id", "tenant_id", name=_("Tenancy")),
95
97
  )
96
98
 
97
99
  name = forms.CharField(
98
100
  required=False,
99
- label="Template name",
101
+ label=_("Template Name"),
100
102
  )
101
103
  nameserver_id = DynamicModelMultipleChoiceField(
102
104
  queryset=NameServer.objects.all(),
103
105
  required=False,
104
- label="Nameservers",
106
+ label=_("Nameservers"),
105
107
  )
106
108
  record_template_id = DynamicModelMultipleChoiceField(
107
109
  queryset=RecordTemplate.objects.all(),
108
110
  required=False,
109
- label="Record templates",
111
+ label=_("Record Templates"),
110
112
  )
111
113
  description = forms.CharField(
112
114
  required=False,
@@ -114,27 +116,27 @@ class ZoneTemplateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
114
116
  registrar_id = DynamicModelMultipleChoiceField(
115
117
  queryset=Registrar.objects.all(),
116
118
  required=False,
117
- label="Registrar",
119
+ label=_("Registrar"),
118
120
  )
119
121
  registrant_id = DynamicModelMultipleChoiceField(
120
122
  queryset=RegistrationContact.objects.all(),
121
123
  required=False,
122
- label="Registrant",
124
+ label=_("Registrant"),
123
125
  )
124
126
  admin_c_id = DynamicModelMultipleChoiceField(
125
127
  queryset=RegistrationContact.objects.all(),
126
128
  required=False,
127
- label="Admin-C",
129
+ label=_("Administrative Contact"),
128
130
  )
129
131
  tech_c_id = DynamicModelMultipleChoiceField(
130
132
  queryset=RegistrationContact.objects.all(),
131
133
  required=False,
132
- label="Tech-C",
134
+ label=_("Technical Contact"),
133
135
  )
134
136
  billing_c_id = DynamicModelMultipleChoiceField(
135
137
  queryset=RegistrationContact.objects.all(),
136
138
  required=False,
137
- label="Billing-C",
139
+ label=_("Billing Contact"),
138
140
  )
139
141
  tag = TagFilterField(ZoneTemplate)
140
142
 
@@ -144,64 +146,64 @@ class ZoneTemplateImportForm(NetBoxModelImportForm):
144
146
  queryset=NameServer.objects.all(),
145
147
  to_field_name="name",
146
148
  required=False,
147
- help_text="Name servers for the zone template",
149
+ label=_("Nameservers"),
148
150
  )
149
151
  record_templates = CSVModelMultipleChoiceField(
150
152
  queryset=RecordTemplate.objects.all(),
151
153
  to_field_name="name",
152
154
  required=False,
153
- help_text="Record templates used by this zone template",
155
+ label=_("Record Remplates"),
154
156
  )
155
157
  registrar = CSVModelChoiceField(
156
158
  queryset=Registrar.objects.all(),
157
159
  required=False,
158
160
  to_field_name="name",
159
- help_text="Registrar the domain is registered with",
160
161
  error_messages={
161
- "invalid_choice": "Registrar not found.",
162
+ "invalid_choice": _("Registrar not found."),
162
163
  },
164
+ label=_("Registrar"),
163
165
  )
164
166
  registrant = CSVModelChoiceField(
165
167
  queryset=RegistrationContact.objects.all(),
166
168
  required=False,
167
169
  to_field_name="contact_id",
168
- help_text="Owner of the domain",
169
170
  error_messages={
170
- "invalid_choice": "Registrant contact ID not found",
171
+ "invalid_choice": _("Registrant contact ID not found"),
171
172
  },
173
+ label=_("Registrant"),
172
174
  )
173
175
  admin_c = CSVModelChoiceField(
174
176
  queryset=RegistrationContact.objects.all(),
175
177
  required=False,
176
178
  to_field_name="contact_id",
177
- help_text="Administrative contact for the domain",
178
179
  error_messages={
179
- "invalid_choice": "Administrative contact ID not found",
180
+ "invalid_choice": _("Administrative contact ID not found"),
180
181
  },
182
+ label=_("Administrative Contact"),
181
183
  )
182
184
  tech_c = CSVModelChoiceField(
183
185
  queryset=RegistrationContact.objects.all(),
184
186
  required=False,
185
187
  to_field_name="contact_id",
186
- help_text="Technical contact for the domain",
187
188
  error_messages={
188
- "invalid_choice": "Technical contact ID not found",
189
+ "invalid_choice": _("Technical contact ID not found"),
189
190
  },
191
+ label=_("Technical Contact"),
190
192
  )
191
193
  billing_c = CSVModelChoiceField(
192
194
  queryset=RegistrationContact.objects.all(),
193
195
  required=False,
194
196
  to_field_name="contact_id",
195
- help_text="Billing contact for the domain",
196
197
  error_messages={
197
- "invalid_choice": "Billing contact ID not found",
198
+ "invalid_choice": _("Billing contact ID not found"),
198
199
  },
200
+ label=_("Billing Contact"),
199
201
  )
200
202
  tenant = CSVModelChoiceField(
201
203
  queryset=Tenant.objects.all(),
202
204
  required=False,
203
205
  to_field_name="name",
204
- help_text="Assigned tenant",
206
+ label=_("Tenant"),
205
207
  )
206
208
 
207
209
  class Meta:
@@ -226,42 +228,49 @@ class ZoneTemplateBulkEditForm(NetBoxModelBulkEditForm):
226
228
  nameservers = DynamicModelMultipleChoiceField(
227
229
  queryset=NameServer.objects.all(),
228
230
  required=False,
231
+ label=_("Nameservers"),
229
232
  )
230
233
  record_templates = DynamicModelMultipleChoiceField(
231
234
  queryset=RecordTemplate.objects.all(),
232
235
  required=False,
236
+ label=_("Record Templates"),
233
237
  )
234
238
  description = forms.CharField(max_length=200, required=False)
235
239
  registrar = DynamicModelChoiceField(
236
240
  queryset=Registrar.objects.all(),
237
241
  required=False,
242
+ label=_("Registrar"),
238
243
  )
239
244
  registrant = DynamicModelChoiceField(
240
245
  queryset=RegistrationContact.objects.all(),
241
246
  required=False,
247
+ label=_("Registrant"),
242
248
  )
243
249
  admin_c = DynamicModelChoiceField(
244
250
  queryset=RegistrationContact.objects.all(),
245
251
  required=False,
246
- label="Administrative Contact",
252
+ label=_("Administrative Contact"),
247
253
  )
248
254
  tech_c = DynamicModelChoiceField(
249
255
  queryset=RegistrationContact.objects.all(),
250
256
  required=False,
251
- label="Technical Contact",
257
+ label=_("Technical Contact"),
252
258
  )
253
259
  billing_c = DynamicModelChoiceField(
254
260
  queryset=RegistrationContact.objects.all(),
255
261
  required=False,
256
- label="Billing Contact",
262
+ label=_("Billing Contact"),
257
263
  )
258
- tenant = CSVModelChoiceField(
264
+ tenant_group = DynamicModelChoiceField(
265
+ queryset=TenantGroup.objects.all(),
266
+ required=False,
267
+ label=_("Tenant Group"),
268
+ )
269
+ tenant = DynamicModelChoiceField(
259
270
  queryset=Tenant.objects.all(),
260
271
  required=False,
261
- to_field_name="name",
262
- help_text="Assigned tenant",
272
+ label=_("Tenant"),
263
273
  )
264
- tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
265
274
 
266
275
  model = ZoneTemplate
267
276
 
@@ -269,11 +278,11 @@ class ZoneTemplateBulkEditForm(NetBoxModelBulkEditForm):
269
278
  FieldSet(
270
279
  "nameservers",
271
280
  "description",
272
- name="Attributes",
281
+ name=_("Attributes"),
273
282
  ),
274
283
  FieldSet(
275
284
  "record_templates",
276
- name="Record Templates",
285
+ name=_("Record Templates"),
277
286
  ),
278
287
  FieldSet(
279
288
  "registrar",
@@ -281,9 +290,9 @@ class ZoneTemplateBulkEditForm(NetBoxModelBulkEditForm):
281
290
  "admin_c",
282
291
  "tech_c",
283
292
  "billing_c",
284
- name="Domain Registration",
293
+ name=_("Domain Registration"),
285
294
  ),
286
- FieldSet("tenant_group", "tenant", name="Tenancy"),
295
+ FieldSet("tenant_group", "tenant", name=_("Tenancy")),
287
296
  )
288
297
 
289
298
  nullable_fields = (
@@ -295,4 +304,5 @@ class ZoneTemplateBulkEditForm(NetBoxModelBulkEditForm):
295
304
  "admin_c",
296
305
  "tech_c",
297
306
  "billing_c",
307
+ "tenant",
298
308
  )
@@ -8,6 +8,13 @@ from netbox_dns.utilities import update_dns_records
8
8
  class Command(BaseCommand):
9
9
  help = "Rebuild DNSsync relationships between IP addresses and records"
10
10
 
11
+ def add_arguments(self, parser):
12
+ parser.add_argument(
13
+ "--force",
14
+ action="store_true",
15
+ help="Update records even if DNS name was not changed (required for rebuilding filtered views",
16
+ )
17
+
11
18
  def handle(self, *model_names, **options):
12
19
  ip_addresses = IPAddress.objects.all()
13
20
  for ip_address in ip_addresses:
@@ -15,4 +22,10 @@ class Command(BaseCommand):
15
22
  self.stdout.write(
16
23
  f"Updating DNS records for IP Address {ip_address}, VRF {ip_address.vrf}"
17
24
  )
18
- update_dns_records(ip_address)
25
+ if (
26
+ update_dns_records(ip_address, force=options.get("force"))
27
+ and options.get("verbosity") >= 1
28
+ ):
29
+ self.stdout.write(
30
+ f"Updated DNS records for IP Address {ip_address}, VRF {ip_address.vrf}"
31
+ )
@@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError
4
4
  from django.db import models, transaction
5
5
  from django.db.models import Q
6
6
  from django.urls import reverse
7
+ from django.utils.translation import gettext_lazy as _
7
8
 
8
9
  from netbox.models import NetBoxModel
9
10
  from netbox.search import SearchIndex, register_search
@@ -29,14 +30,17 @@ __all__ = (
29
30
 
30
31
  class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
31
32
  name = models.CharField(
33
+ verbose_name=_("Name"),
32
34
  unique=True,
33
35
  max_length=255,
34
36
  )
35
37
  description = models.CharField(
38
+ verbose_name=_("Description"),
36
39
  max_length=200,
37
40
  blank=True,
38
41
  )
39
42
  tenant = models.ForeignKey(
43
+ verbose_name=_("Tenant"),
40
44
  to="tenancy.Tenant",
41
45
  on_delete=models.PROTECT,
42
46
  related_name="netbox_dns_nameservers",
@@ -50,8 +54,8 @@ class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
50
54
  )
51
55
 
52
56
  class Meta:
53
- verbose_name = "Nameserver"
54
- verbose_name_plural = "Nameservers"
57
+ verbose_name = _("Nameserver")
58
+ verbose_name_plural = _("Nameservers")
55
59
 
56
60
  ordering = ("name",)
57
61
 
@@ -8,6 +8,7 @@ from django.db import transaction, models
8
8
  from django.db.models import Q, ExpressionWrapper, BooleanField, Min
9
9
  from django.urls import reverse
10
10
  from django.conf import settings
11
+ from django.utils.translation import gettext_lazy as _
11
12
 
12
13
  from netbox.models import NetBoxModel
13
14
  from ipam.models import IPAddress
@@ -33,6 +34,9 @@ __all__ = (
33
34
  "RecordIndex",
34
35
  )
35
36
 
37
+ ZONE_ACTIVE_STATUS_LIST = get_plugin_config("netbox_dns", "zone_active_status")
38
+ RECORD_ACTIVE_STATUS_LIST = get_plugin_config("netbox_dns", "record_active_status")
39
+
36
40
 
37
41
  def min_ttl(*ttl_list):
38
42
  return min((ttl for ttl in ttl_list if ttl is not None), default=None)
@@ -101,14 +105,14 @@ class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
101
105
  .annotate(
102
106
  active=ExpressionWrapper(
103
107
  Q(
104
- Q(zone__status__in=zone.Zone.ACTIVE_STATUS_LIST)
108
+ Q(zone__status__in=ZONE_ACTIVE_STATUS_LIST)
105
109
  & Q(
106
110
  Q(address_record__isnull=True)
107
111
  | Q(
108
- address_record__zone__status__in=zone.Zone.ACTIVE_STATUS_LIST
112
+ address_record__zone__status__in=ZONE_ACTIVE_STATUS_LIST
109
113
  )
110
114
  )
111
- & Q(status__in=Record.ACTIVE_STATUS_LIST)
115
+ & Q(status__in=RECORD_ACTIVE_STATUS_LIST)
112
116
  ),
113
117
  output_field=BooleanField(),
114
118
  )
@@ -117,66 +121,73 @@ class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
117
121
 
118
122
 
119
123
  class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
120
- ACTIVE_STATUS_LIST = (RecordStatusChoices.STATUS_ACTIVE,)
121
-
122
124
  unique_ptr_qs = Q(
123
125
  Q(disable_ptr=False),
124
126
  Q(Q(type=RecordTypeChoices.A) | Q(type=RecordTypeChoices.AAAA)),
125
127
  )
126
128
 
127
129
  name = models.CharField(
130
+ verbose_name=_("Name"),
128
131
  max_length=255,
129
132
  )
130
133
  zone = models.ForeignKey(
131
- "Zone",
134
+ verbose_name=_("Zone"),
135
+ to="Zone",
132
136
  on_delete=models.CASCADE,
133
137
  )
134
138
  fqdn = models.CharField(
139
+ verbose_name=_("FQDN"),
135
140
  max_length=255,
136
141
  null=True,
137
142
  blank=True,
138
143
  default=None,
139
144
  )
140
145
  type = models.CharField(
146
+ verbose_name=_("Type"),
141
147
  choices=RecordTypeChoices,
142
148
  max_length=10,
143
149
  )
144
150
  value = models.CharField(
151
+ verbose_name=_("Value"),
145
152
  max_length=65535,
146
153
  )
147
154
  status = models.CharField(
155
+ verbose_name=_("Status"),
148
156
  max_length=50,
149
157
  choices=RecordStatusChoices,
150
158
  default=RecordStatusChoices.STATUS_ACTIVE,
151
159
  blank=False,
152
160
  )
153
161
  ttl = models.PositiveIntegerField(
154
- verbose_name="TTL",
162
+ verbose_name=_("TTL"),
155
163
  null=True,
156
164
  blank=True,
157
165
  )
158
166
  managed = models.BooleanField(
167
+ verbose_name=_("Managed"),
159
168
  null=False,
160
169
  default=False,
161
170
  )
162
171
  ptr_record = models.OneToOneField(
163
- "self",
172
+ verbose_name="PTR Record",
173
+ to="self",
164
174
  on_delete=models.SET_NULL,
165
175
  related_name="address_record",
166
- verbose_name="PTR record",
167
176
  null=True,
168
177
  blank=True,
169
178
  )
170
179
  disable_ptr = models.BooleanField(
171
- verbose_name="Disable PTR",
172
- help_text="Disable PTR record creation",
180
+ verbose_name=_("Disable PTR"),
181
+ help_text=_("Disable PTR record creation"),
173
182
  default=False,
174
183
  )
175
184
  description = models.CharField(
185
+ verbose_name=_("Description"),
176
186
  max_length=200,
177
187
  blank=True,
178
188
  )
179
189
  tenant = models.ForeignKey(
190
+ verbose_name=_("Tenant"),
180
191
  to="tenancy.Tenant",
181
192
  on_delete=models.PROTECT,
182
193
  related_name="netbox_dns_records",
@@ -184,13 +195,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
184
195
  null=True,
185
196
  )
186
197
  ip_address = AddressField(
187
- verbose_name="Related IP Address",
188
- help_text="IP address related to an address (A/AAAA) or PTR record",
198
+ verbose_name=_("Related IP Address"),
199
+ help_text=_("IP address related to an address (A/AAAA) or PTR record"),
189
200
  blank=True,
190
201
  null=True,
191
202
  )
192
203
  ipam_ip_address = models.ForeignKey(
193
- verbose_name="IPAM IP Address",
204
+ verbose_name=_("IPAM IP Address"),
194
205
  to="ipam.IPAddress",
195
206
  on_delete=models.CASCADE,
196
207
  related_name="netbox_dns_records",
@@ -198,10 +209,10 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
198
209
  null=True,
199
210
  )
200
211
  rfc2317_cname_record = models.ForeignKey(
201
- "self",
212
+ verbose_name=_("RFC2317 CNAME Record"),
213
+ to="self",
202
214
  on_delete=models.SET_NULL,
203
215
  related_name="rfc2317_ptr_records",
204
- verbose_name="RFC2317 CNAME record",
205
216
  null=True,
206
217
  blank=True,
207
218
  )
@@ -221,8 +232,8 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
221
232
  )
222
233
 
223
234
  class Meta:
224
- verbose_name = "Record"
225
- verbose_name_plural = "Records"
235
+ verbose_name = _("Record")
236
+ verbose_name_plural = _("Records")
226
237
 
227
238
  ordering = (
228
239
  "fqdn",
@@ -285,8 +296,8 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
285
296
  @property
286
297
  def is_active(self):
287
298
  return (
288
- self.status in Record.ACTIVE_STATUS_LIST
289
- and self.zone.status in zone.Zone.ACTIVE_STATUS_LIST
299
+ self.status in RECORD_ACTIVE_STATUS_LIST
300
+ and self.zone.status in ZONE_ACTIVE_STATUS_LIST
290
301
  )
291
302
 
292
303
  @property
@@ -537,7 +548,9 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
537
548
  if not fqdn.is_subdomain(_zone):
538
549
  raise ValidationError(
539
550
  {
540
- "name": f"{self.name} is not a name in {zone.name}",
551
+ "name": _("{name} is not a name in {zone}").format(
552
+ name=self.name, zone=zone.name
553
+ ),
541
554
  }
542
555
  )
543
556
 
@@ -581,13 +594,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
581
594
  {
582
595
  "name": exc,
583
596
  }
584
- ) from None
597
+ )
585
598
 
586
599
  def validate_value(self):
587
600
  try:
588
- validate_record_value(self.type, self.value)
601
+ validate_record_value(self)
589
602
  except ValidationError as exc:
590
- raise ValidationError({"value": exc}) from None
603
+ raise ValidationError({"value": exc})
591
604
 
592
605
  def check_unique_record(self, new_zone=None):
593
606
  if not get_plugin_config("netbox_dns", "enforce_unique_records", False):
@@ -604,7 +617,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
604
617
  name=self.name,
605
618
  type=self.type,
606
619
  value=self.value,
607
- status__in=Record.ACTIVE_STATUS_LIST,
620
+ status__in=RECORD_ACTIVE_STATUS_LIST,
608
621
  )
609
622
 
610
623
  if not self._state.adding:
@@ -621,9 +634,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
621
634
 
622
635
  raise ValidationError(
623
636
  {
624
- "value": f"There is already an active {self.type} record for name {self.name} in zone {self.zone} with value {self.value}."
637
+ "value": _(
638
+ "There is already an active {type} record for name {name} in zone {zone} with value {value}."
639
+ ).format(
640
+ type=self.type, name=self.name, zone=self.zone, value=self.value
641
+ )
625
642
  }
626
- ) from None
643
+ )
627
644
 
628
645
  def handle_conflicting_address_records(self):
629
646
  if self.ipam_ip_address is None or not self.is_active:
@@ -637,7 +654,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
637
654
  name=self.name,
638
655
  type=self.type,
639
656
  value=self.value,
640
- status__in=Record.ACTIVE_STATUS_LIST,
657
+ status__in=RECORD_ACTIVE_STATUS_LIST,
641
658
  ipam_ip_address__isnull=True,
642
659
  )
643
660
 
@@ -680,9 +697,16 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
680
697
  conflicting_ttls = ", ".join({str(record.ttl) for record in records})
681
698
  raise ValidationError(
682
699
  {
683
- "ttl": f"There is at least one active {self.type} record for name {self.name} in zone {self.zone} and TTL is different ({conflicting_ttls})."
700
+ "ttl": _(
701
+ "There is at least one active {type} record for name {name} in zone {zone} and TTL is different ({ttls})."
702
+ ).format(
703
+ type=self.type,
704
+ name=self.name,
705
+ zone=self.zone,
706
+ ttls=conflicting_ttls,
707
+ )
684
708
  }
685
- ) from None
709
+ )
686
710
 
687
711
  def update_rrset_ttl(self, ttl=None):
688
712
  if self._state.adding:
@@ -760,24 +784,30 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
760
784
  ):
761
785
  raise ValidationError(
762
786
  {
763
- "value": f"There is already an active record for name {ptr_cname_name} in zone {ptr_cname_zone}, RFC2317 CNAME is not allowed."
787
+ "value": _(
788
+ "There is already an active record for name {name} in zone {zone}, RFC2317 CNAME is not allowed."
789
+ ).format(name=ptr_cname_name, zone=ptr_cname_zone)
764
790
  }
765
- ) from None
791
+ )
766
792
 
767
793
  if self.type == RecordTypeChoices.SOA and self.name != "@":
768
794
  raise ValidationError(
769
795
  {
770
- "name": "SOA records are only allowed with name @ and are created automatically by NetBox DNS"
796
+ "name": _(
797
+ "SOA records are only allowed with name @ and are created automatically by NetBox DNS"
798
+ )
771
799
  }
772
- ) from None
800
+ )
773
801
 
774
802
  if self.type == RecordTypeChoices.CNAME:
775
803
  if records.exclude(type=RecordTypeChoices.NSEC).exists():
776
804
  raise ValidationError(
777
805
  {
778
- "type": f"There is already an active record for name {self.name} in zone {self.zone}, CNAME is not allowed."
806
+ "type": _(
807
+ "There is already an active record for name {name} in zone {zone}, CNAME is not allowed."
808
+ ).format(name=self.name, zone=self.zone)
779
809
  }
780
- ) from None
810
+ )
781
811
 
782
812
  elif (
783
813
  records.filter(type=RecordTypeChoices.CNAME).exists()
@@ -785,17 +815,21 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
785
815
  ):
786
816
  raise ValidationError(
787
817
  {
788
- "type": f"There is already an active CNAME record for name {self.name} in zone {self.zone}, no other record allowed."
818
+ "type": _(
819
+ "There is already an active CNAME record for name {name} in zone {zone}, no other record allowed."
820
+ ).format(name=self.name, zone=self.zone)
789
821
  }
790
- ) from None
822
+ )
791
823
 
792
824
  elif self.type in RecordTypeChoices.SINGLETONS:
793
825
  if records.filter(type=self.type).exists():
794
826
  raise ValidationError(
795
827
  {
796
- "type": f"There is already an active {self.type} record for name {self.name} in zone {self.zone}, more than one are not allowed."
828
+ "type": _(
829
+ "There is already an active {type} record for name {name} in zone {zone}, more than one are not allowed."
830
+ ).format(type=self.type, name=self.name, zone=self.zone)
797
831
  }
798
- ) from None
832
+ )
799
833
 
800
834
  super().clean(*args, **kwargs)
801
835