netbox-plugin-dns 1.0b2__py3-none-any.whl → 1.0.2__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 (40) hide show
  1. netbox_dns/__init__.py +3 -3
  2. netbox_dns/api/serializers_/view.py +6 -1
  3. netbox_dns/fields/network.py +20 -21
  4. netbox_dns/fields/rfc2317.py +2 -2
  5. netbox_dns/filtersets/view.py +1 -1
  6. netbox_dns/filtersets/zone.py +4 -4
  7. netbox_dns/forms/record.py +30 -2
  8. netbox_dns/forms/view.py +6 -3
  9. netbox_dns/forms/zone.py +71 -102
  10. netbox_dns/graphql/types.py +1 -4
  11. netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +4 -2
  12. netbox_dns/migrations/0003_default_view.py +15 -0
  13. netbox_dns/migrations/0004_create_and_assign_default_view.py +26 -0
  14. netbox_dns/migrations/0005_alter_zone_view_not_null.py +18 -0
  15. netbox_dns/mixins/__init__.py +1 -0
  16. netbox_dns/mixins/object_modification.py +26 -0
  17. netbox_dns/models/nameserver.py +7 -6
  18. netbox_dns/models/record.py +94 -35
  19. netbox_dns/models/view.py +56 -1
  20. netbox_dns/models/zone.py +101 -67
  21. netbox_dns/signals/ipam_coupling.py +1 -2
  22. netbox_dns/tables/view.py +12 -2
  23. netbox_dns/template_content.py +1 -1
  24. netbox_dns/templates/netbox_dns/record.html +1 -1
  25. netbox_dns/templates/netbox_dns/view.html +4 -0
  26. netbox_dns/templates/netbox_dns/zone.html +2 -4
  27. netbox_dns/urls/__init__.py +17 -0
  28. netbox_dns/urls/contact.py +51 -0
  29. netbox_dns/urls/nameserver.py +69 -0
  30. netbox_dns/urls/record.py +41 -0
  31. netbox_dns/urls/registrar.py +63 -0
  32. netbox_dns/urls/view.py +39 -0
  33. netbox_dns/urls/zone.py +57 -0
  34. netbox_dns/validators/dns_name.py +24 -11
  35. netbox_dns/views/record.py +10 -18
  36. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/LICENSE +2 -1
  37. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/METADATA +15 -14
  38. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/RECORD +39 -28
  39. netbox_dns/urls.py +0 -297
  40. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/WHEEL +0 -0
netbox_dns/models/zone.py CHANGED
@@ -15,15 +15,15 @@ from django.db.models import Q, Max, ExpressionWrapper, BooleanField
15
15
  from django.urls import reverse
16
16
  from django.db.models.signals import m2m_changed
17
17
  from django.dispatch import receiver
18
+ from django.conf import settings
18
19
 
19
20
  from netbox.models import NetBoxModel
20
21
  from netbox.search import SearchIndex, register_search
22
+ from netbox.plugins.utils import get_plugin_config
21
23
  from utilities.querysets import RestrictedQuerySet
22
24
  from utilities.choices import ChoiceSet
23
25
  from ipam.models import IPAddress
24
26
 
25
- from netbox.plugins.utils import get_plugin_config
26
-
27
27
  from netbox_dns.fields import NetworkField, RFC2317NetworkField
28
28
  from netbox_dns.utilities import (
29
29
  arpa_to_prefix,
@@ -35,11 +35,14 @@ from netbox_dns.validators import (
35
35
  validate_fqdn,
36
36
  validate_domain_name,
37
37
  )
38
+ from netbox_dns.mixins import ObjectModificationMixin
38
39
 
39
40
  # +
40
- # This is a hack designed to break cyclic imports between Record and Zone
41
+ # This is a hack designed to break cyclic imports between View, Record and Zone
41
42
  # -
42
43
  import netbox_dns.models.record as record
44
+ import netbox_dns.models.view as view
45
+ import netbox_dns.models.nameserver as nameserver
43
46
 
44
47
 
45
48
  class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
@@ -75,14 +78,13 @@ class ZoneStatusChoices(ChoiceSet):
75
78
  ]
76
79
 
77
80
 
78
- class Zone(NetBoxModel):
81
+ class Zone(ObjectModificationMixin, NetBoxModel):
79
82
  ACTIVE_STATUS_LIST = (ZoneStatusChoices.STATUS_ACTIVE,)
80
83
 
81
84
  view = models.ForeignKey(
82
85
  to="View",
83
86
  on_delete=models.PROTECT,
84
- blank=True,
85
- null=True,
87
+ null=False,
86
88
  )
87
89
  name = models.CharField(
88
90
  max_length=255,
@@ -285,11 +287,20 @@ class Zone(NetBoxModel):
285
287
  except dns_name.IDNAException:
286
288
  name = self.name
287
289
 
288
- if self.view:
290
+ if not self.view.default_view:
289
291
  return f"[{self.view}] {name}"
290
292
 
291
293
  return str(name)
292
294
 
295
+ @staticmethod
296
+ def get_defaults():
297
+ return {
298
+ field[5:]: value
299
+ for field, value in settings.PLUGINS_CONFIG.get("netbox_dns").items()
300
+ if field.startswith("zone_")
301
+ and field not in ("zone_soa_mname", "zone_nameservers")
302
+ }
303
+
293
304
  @property
294
305
  def display_name(self):
295
306
  return name_to_unicode(self.name)
@@ -317,11 +328,11 @@ class Zone(NetBoxModel):
317
328
 
318
329
  def get_rfc2317_parent_zone(self):
319
330
  if not self.is_rfc2317_zone:
320
- return
331
+ return None
321
332
 
322
333
  return (
323
334
  Zone.objects.filter(
324
- self.view_filter,
335
+ view=self.view,
325
336
  arpa_network__net_contains=self.rfc2317_prefix,
326
337
  )
327
338
  .order_by("arpa_network__net_mask_length")
@@ -342,12 +353,6 @@ class Zone(NetBoxModel):
342
353
  )
343
354
  )
344
355
 
345
- @property
346
- def view_filter(self):
347
- if self.view is None:
348
- return Q(view__isnull=True)
349
- return Q(view=self.view)
350
-
351
356
  def record_count(self, managed=False):
352
357
  return record.Record.objects.filter(zone=self, managed=managed).count()
353
358
 
@@ -417,19 +422,15 @@ class Zone(NetBoxModel):
417
422
  if not nameservers:
418
423
  ns_errors.append(f"No nameservers are configured for zone {self}")
419
424
 
420
- for nameserver in nameservers:
421
- name = dns_name.from_text(nameserver.name, origin=None)
425
+ for _nameserver in nameservers:
426
+ name = dns_name.from_text(_nameserver.name, origin=None)
422
427
  parent = name.parent()
423
428
 
424
429
  if len(parent) < 2:
425
430
  continue
426
431
 
427
- view_condition = (
428
- Q(view__isnull=True) if self.view is None else Q(view_id=self.view.pk)
429
- )
430
-
431
432
  try:
432
- ns_zone = Zone.objects.get(view_condition, name=parent.to_text())
433
+ ns_zone = Zone.objects.get(view_id=self.view.pk, name=parent.to_text())
433
434
  except ObjectDoesNotExist:
434
435
  continue
435
436
 
@@ -437,7 +438,7 @@ class Zone(NetBoxModel):
437
438
  address_records = record.Record.objects.filter(
438
439
  Q(zone=ns_zone),
439
440
  Q(status__in=record.Record.ACTIVE_STATUS_LIST),
440
- Q(Q(name=f"{nameserver.name}.") | Q(name=relative_name)),
441
+ Q(Q(name=f"{_nameserver.name}.") | Q(name=relative_name)),
441
442
  Q(
442
443
  Q(type=record.RecordTypeChoices.A)
443
444
  | Q(type=record.RecordTypeChoices.AAAA)
@@ -446,11 +447,23 @@ class Zone(NetBoxModel):
446
447
 
447
448
  if not address_records:
448
449
  ns_warnings.append(
449
- f"Nameserver {nameserver.name} does not have an active address record in zone {ns_zone}"
450
+ f"Nameserver {_nameserver.name} does not have an active address record in zone {ns_zone}"
450
451
  )
451
452
 
452
453
  return ns_warnings, ns_errors
453
454
 
455
+ def check_soa_serial_increment(self, old_serial, new_serial):
456
+ MAX_SOA_SERIAL_INCREMENT = 2**31 - 1
457
+ SOA_SERIAL_WRAP = 2**32
458
+
459
+ if old_serial is None:
460
+ return
461
+
462
+ if (new_serial - old_serial) % SOA_SERIAL_WRAP > MAX_SOA_SERIAL_INCREMENT:
463
+ raise ValidationError(
464
+ {"soa_serial": f"soa_serial must not decrease for zone {self.name}."}
465
+ )
466
+
454
467
  def get_auto_serial(self):
455
468
  records = record.Record.objects.filter(zone_id=self.pk).exclude(
456
469
  type=record.RecordTypeChoices.SOA
@@ -492,19 +505,6 @@ class Zone(NetBoxModel):
492
505
  def network_from_name(self):
493
506
  return arpa_to_prefix(self.name)
494
507
 
495
- def check_name_conflict(self):
496
- if self.view is None:
497
- if (
498
- Zone.objects.exclude(pk=self.pk)
499
- .filter(name=self.name.rstrip("."), view__isnull=True)
500
- .exists()
501
- ):
502
- raise ValidationError(
503
- {
504
- "name": f"A zone with name {self.name} and no view already exists."
505
- }
506
- )
507
-
508
508
  def update_rfc2317_parent_zone(self):
509
509
  if not self.is_rfc2317_zone:
510
510
  return
@@ -555,8 +555,33 @@ class Zone(NetBoxModel):
555
555
  ptr_zone.save_soa_serial()
556
556
  ptr_zone.update_soa_record()
557
557
 
558
+ def clean_fields(self, exclude=None):
559
+ defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
560
+
561
+ if self.view_id is None:
562
+ self.view_id = view.View.get_default_view().pk
563
+
564
+ for field, value in self.get_defaults().items():
565
+ if getattr(self, field) in (None, ""):
566
+ if value not in (None, ""):
567
+ setattr(self, field, value)
568
+
569
+ if self.soa_mname_id is None:
570
+ default_soa_mname = defaults.get("zone_soa_mname")
571
+ try:
572
+ self.soa_mname = nameserver.NameServer.objects.get(
573
+ name=default_soa_mname
574
+ )
575
+ except nameserver.NameServer.DoesNotExist:
576
+ raise ValidationError(
577
+ f"Default soa_mname instance {default_soa_mname} does not exist"
578
+ )
579
+
580
+ super().clean_fields(exclude=exclude)
581
+
558
582
  def clean(self, *args, **kwargs):
559
- self.check_name_conflict()
583
+ if self.soa_ttl is None:
584
+ self.soa_ttl = self.default_ttl
560
585
 
561
586
  try:
562
587
  self.name = normalize_name(self.name)
@@ -576,6 +601,8 @@ class Zone(NetBoxModel):
576
601
  }
577
602
  ) from None
578
603
 
604
+ if self.soa_rname in (None, ""):
605
+ raise ValidationError("soa_rname not set and no default value defined")
579
606
  try:
580
607
  dns_name.from_text(self.soa_rname, origin=dns_name.root)
581
608
  validate_fqdn(self.soa_rname)
@@ -586,12 +613,29 @@ class Zone(NetBoxModel):
586
613
  }
587
614
  ) from None
588
615
 
589
- if self.soa_serial is None and not self.soa_serial_auto:
590
- raise ValidationError(
591
- {
592
- "soa_serial": f"soa_serial is not defined and soa_serial_auto is disabled for zone {self.name}."
593
- }
594
- )
616
+ if not self.soa_serial_auto:
617
+ if self.soa_serial is None:
618
+ raise ValidationError(
619
+ {
620
+ "soa_serial": f"soa_serial is not defined and soa_serial_auto is disabled for zone {self.name}."
621
+ }
622
+ )
623
+
624
+ if self.pk is not None:
625
+ old_zone = Zone.objects.get(pk=self.pk)
626
+ if not self.soa_serial_auto:
627
+ self.check_soa_serial_increment(old_zone.soa_serial, self.soa_serial)
628
+ else:
629
+ try:
630
+ self.check_soa_serial_increment(
631
+ old_zone.soa_serial, self.get_auto_serial()
632
+ )
633
+ except ValidationError:
634
+ raise ValidationError(
635
+ {
636
+ "soa_serial_auto": f"Enabling soa_serial_auto would decrease soa_serial for zone {self.name}."
637
+ }
638
+ )
595
639
 
596
640
  if self.is_reverse_zone:
597
641
  self.arpa_network = self.network_from_name
@@ -619,7 +663,7 @@ class Zone(NetBoxModel):
619
663
  self.rfc2317_parent_zone = None
620
664
 
621
665
  overlapping_zones = Zone.objects.filter(
622
- self.view_filter,
666
+ view=self.view,
623
667
  rfc2317_prefix__net_overlap=self.rfc2317_prefix,
624
668
  active=True,
625
669
  ).exclude(pk=self.pk)
@@ -635,20 +679,12 @@ class Zone(NetBoxModel):
635
679
  self.rfc2317_parent_managed = False
636
680
  self.rfc2317_parent_zone = None
637
681
 
682
+ super().clean(*args, **kwargs)
683
+
638
684
  def save(self, *args, **kwargs):
639
685
  self.full_clean()
640
686
 
641
- new_zone = self.pk is None
642
- if not new_zone:
643
- old_zone = Zone.objects.get(pk=self.pk)
644
-
645
- name_changed = not new_zone and old_zone.name != self.name
646
- view_changed = not new_zone and old_zone.view != self.view
647
- status_changed = not new_zone and old_zone.status != self.status
648
- rfc2317_changed = not new_zone and (
649
- old_zone.rfc2317_prefix != self.rfc2317_prefix
650
- or old_zone.rfc2317_parent_managed != self.rfc2317_parent_managed
651
- )
687
+ changed_fields = self.changed_fields
652
688
 
653
689
  if self.soa_serial_auto:
654
690
  self.soa_serial = self.get_auto_serial()
@@ -656,10 +692,10 @@ class Zone(NetBoxModel):
656
692
  super().save(*args, **kwargs)
657
693
 
658
694
  if (
659
- new_zone or name_changed or view_changed or status_changed
695
+ changed_fields is None or {"name", "view", "status"} & changed_fields
660
696
  ) and self.is_reverse_zone:
661
697
  zones = Zone.objects.filter(
662
- self.view_filter,
698
+ view=self.view,
663
699
  arpa_network__net_contains_or_equals=self.arpa_network,
664
700
  )
665
701
  address_records = record.Record.objects.filter(
@@ -688,14 +724,12 @@ class Zone(NetBoxModel):
688
724
  child_zone.update_rfc2317_parent_zone()
689
725
 
690
726
  if (
691
- new_zone
692
- or name_changed
693
- or view_changed
694
- or status_changed
695
- or rfc2317_changed
727
+ changed_fields is None
728
+ or {"name", "view", "status", "rfc2317_prefix", "rfc2317_parent_managed"}
729
+ & changed_fields
696
730
  ) and self.is_rfc2317_zone:
697
731
  zones = Zone.objects.filter(
698
- self.view_filter,
732
+ view=self.view,
699
733
  arpa_network__net_contains=self.rfc2317_prefix,
700
734
  )
701
735
  address_records = record.Record.objects.filter(
@@ -718,7 +752,7 @@ class Zone(NetBoxModel):
718
752
 
719
753
  self.update_rfc2317_parent_zone()
720
754
 
721
- elif name_changed or view_changed or status_changed:
755
+ elif changed_fields is not None and {"name", "view", "status"} & changed_fields:
722
756
  for address_record in self.record_set.filter(
723
757
  type__in=(record.RecordTypeChoices.A, record.RecordTypeChoices.AAAA)
724
758
  ):
@@ -727,7 +761,7 @@ class Zone(NetBoxModel):
727
761
  # Fix name in IP Address when zone name is changed
728
762
  if (
729
763
  get_plugin_config("netbox_dns", "feature_ipam_coupling")
730
- and name_changed
764
+ and "name" in changed_fields
731
765
  ):
732
766
  for ip in IPAddress.objects.filter(
733
767
  custom_field_data__ipaddress_dns_zone_id=self.pk
@@ -735,7 +769,7 @@ class Zone(NetBoxModel):
735
769
  ip.dns_name = f'{ip.custom_field_data["ipaddress_dns_record_name"]}.{self.name}'
736
770
  ip.save(update_fields=["dns_name"])
737
771
 
738
- if name_changed:
772
+ if changed_fields is not None and "name" in changed_fields:
739
773
  for _record in self.record_set.all():
740
774
  _record.save(
741
775
  update_fields=["fqdn"],
@@ -5,6 +5,7 @@ from rest_framework.exceptions import PermissionDenied as APIPermissionDenied
5
5
 
6
6
  from netbox.signals import post_clean
7
7
  from netbox.context import current_request
8
+ from netbox.plugins.utils import get_plugin_config
8
9
  from ipam.models import IPAddress
9
10
 
10
11
  from netbox_dns.models import Zone
@@ -18,8 +19,6 @@ from netbox_dns.utilities.ipam_coupling import (
18
19
  DNSPermissionDenied,
19
20
  )
20
21
 
21
- from netbox.plugins.utils import get_plugin_config
22
-
23
22
 
24
23
  @receiver(post_clean, sender=IPAddress)
25
24
  def ip_address_check_permissions_save(instance, **kwargs):
netbox_dns/tables/view.py CHANGED
@@ -10,9 +10,19 @@ class ViewTable(TenancyColumnsMixin, NetBoxTable):
10
10
  name = tables.Column(
11
11
  linkify=True,
12
12
  )
13
+ default_view = tables.BooleanColumn(
14
+ verbose_name="Default View",
15
+ )
13
16
  tags = TagColumn(url_name="plugins:netbox_dns:view_list")
14
17
 
15
18
  class Meta(NetBoxTable.Meta):
16
19
  model = View
17
- fields = ("name", "description", "tenant", "tenant_group", "tags")
18
- default_columns = ("name",)
20
+ fields = (
21
+ "name",
22
+ "default_view",
23
+ "description",
24
+ "tenant",
25
+ "tenant_group",
26
+ "tags",
27
+ )
28
+ default_columns = ("name", "default_view")
@@ -117,7 +117,7 @@ class RelatedDNSObjects(PluginTemplateExtension):
117
117
  )
118
118
 
119
119
 
120
- template_extensions = list()
120
+ template_extensions = []
121
121
 
122
122
  if version.parse(settings.VERSION) < version.parse("3.7.0"):
123
123
  template_extensions.append(RelatedDNSObjects)
@@ -56,7 +56,7 @@
56
56
  <td><a href="{% url 'plugins:netbox_dns:zone_records' pk=object.zone.pk %}">{{ object.zone }}</a></td>
57
57
  {% endif %}
58
58
  </tr>
59
- {% if not object.managed %}
59
+ {% if not object.managed or object.tenant %}
60
60
  <tr>
61
61
  <th scope="row">Tenant</th>
62
62
  <td>
@@ -10,6 +10,10 @@
10
10
  <th scope="row">Name</th>
11
11
  <td>{{ object.name }}</td>
12
12
  </tr>
13
+ <tr>
14
+ <th scope="row">Default View</th>
15
+ <td>{% checkmark object.default_view %}</td>
16
+ </tr>
13
17
  {% if object.description %}
14
18
  <tr>
15
19
  <th scope="row">Description</th>
@@ -20,7 +20,6 @@
20
20
  <td>{{ unicode_name }}</td>
21
21
  </tr>
22
22
  {% endif %}
23
- {% if object.view %}
24
23
  <tr>
25
24
  <th scope="row">View</th>
26
25
  <td>
@@ -29,7 +28,6 @@
29
28
  </a>
30
29
  </td>
31
30
  </tr>
32
- {% endif %}
33
31
  {% if object.description %}
34
32
  <tr>
35
33
  <th scope="row">Description</th>
@@ -116,11 +114,11 @@
116
114
  <td>{{ object.soa_ttl }}</td>
117
115
  </tr>
118
116
  <tr>
119
- <th scope="row">Primary Nameserver</th>
117
+ <th scope="row">MName</th>
120
118
  <td><a href="{% url 'plugins:netbox_dns:nameserver' pk=object.soa_mname.pk %}">{{ object.soa_mname }}</a></td>
121
119
  </tr>
122
120
  <tr>
123
- <th scope="row">Responsible</th>
121
+ <th scope="row">RName</th>
124
122
  <td>{{ object.soa_rname }}</td>
125
123
  </tr>
126
124
  {% if object.soa_serial_auto %}
@@ -0,0 +1,17 @@
1
+ from .contact import contact_urlpatterns
2
+ from .nameserver import nameserver_urlpatterns
3
+ from .record import record_urlpatterns
4
+ from .registrar import registrar_urlpatterns
5
+ from .view import view_urlpatterns
6
+ from .zone import zone_urlpatterns
7
+
8
+ app_name = "netbox_dns"
9
+
10
+ urlpatterns = (
11
+ contact_urlpatterns
12
+ + nameserver_urlpatterns
13
+ + record_urlpatterns
14
+ + registrar_urlpatterns
15
+ + view_urlpatterns
16
+ + zone_urlpatterns
17
+ )
@@ -0,0 +1,51 @@
1
+ from django.urls import path
2
+
3
+ from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
4
+
5
+ from netbox_dns.models import Contact
6
+ from netbox_dns.views import (
7
+ ContactListView,
8
+ ContactView,
9
+ ContactDeleteView,
10
+ ContactEditView,
11
+ ContactBulkImportView,
12
+ ContactBulkEditView,
13
+ ContactBulkDeleteView,
14
+ ContactZoneListView,
15
+ )
16
+
17
+ contact_urlpatterns = [
18
+ path("contacts/", ContactListView.as_view(), name="contact_list"),
19
+ path("contacts/add/", ContactEditView.as_view(), name="contact_add"),
20
+ path("contacts/import/", ContactBulkImportView.as_view(), name="contact_import"),
21
+ path("contacts/edit/", ContactBulkEditView.as_view(), name="contact_bulk_edit"),
22
+ path(
23
+ "contacts/delete/",
24
+ ContactBulkDeleteView.as_view(),
25
+ name="contact_bulk_delete",
26
+ ),
27
+ path("contacts/<int:pk>/", ContactView.as_view(), name="contact"),
28
+ path("contacts/<int:pk>/edit/", ContactEditView.as_view(), name="contact_edit"),
29
+ path(
30
+ "contacts/<int:pk>/delete/",
31
+ ContactDeleteView.as_view(),
32
+ name="contact_delete",
33
+ ),
34
+ path(
35
+ "contacts/<int:pk>/zones/",
36
+ ContactZoneListView.as_view(),
37
+ name="contact_zones",
38
+ ),
39
+ path(
40
+ "contacts/<int:pk>/journal/",
41
+ ObjectJournalView.as_view(),
42
+ name="contact_journal",
43
+ kwargs={"model": Contact},
44
+ ),
45
+ path(
46
+ "contacts/<int:pk>/changelog/",
47
+ ObjectChangeLogView.as_view(),
48
+ name="contact_changelog",
49
+ kwargs={"model": Contact},
50
+ ),
51
+ ]
@@ -0,0 +1,69 @@
1
+ from django.urls import path
2
+
3
+ from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
4
+
5
+ from netbox_dns.models import NameServer
6
+ from netbox_dns.views import (
7
+ NameServerListView,
8
+ NameServerView,
9
+ NameServerEditView,
10
+ NameServerDeleteView,
11
+ NameServerBulkImportView,
12
+ NameServerBulkEditView,
13
+ NameServerBulkDeleteView,
14
+ NameServerZoneListView,
15
+ NameServerSOAZoneListView,
16
+ )
17
+
18
+ nameserver_urlpatterns = [
19
+ path("nameservers/", NameServerListView.as_view(), name="nameserver_list"),
20
+ path("nameservers/add/", NameServerEditView.as_view(), name="nameserver_add"),
21
+ path(
22
+ "nameservers/import/",
23
+ NameServerBulkImportView.as_view(),
24
+ name="nameserver_import",
25
+ ),
26
+ path(
27
+ "nameservers/edit/",
28
+ NameServerBulkEditView.as_view(),
29
+ name="nameserver_bulk_edit",
30
+ ),
31
+ path(
32
+ "nameservers/delete/",
33
+ NameServerBulkDeleteView.as_view(),
34
+ name="nameserver_bulk_delete",
35
+ ),
36
+ path("nameservers/<int:pk>/", NameServerView.as_view(), name="nameserver"),
37
+ path(
38
+ "nameservers/<int:pk>/edit",
39
+ NameServerEditView.as_view(),
40
+ name="nameserver_edit",
41
+ ),
42
+ path(
43
+ "nameservers/<int:pk>/delete",
44
+ NameServerDeleteView.as_view(),
45
+ name="nameserver_delete",
46
+ ),
47
+ path(
48
+ "nameservers/<int:pk>/journal/",
49
+ ObjectJournalView.as_view(),
50
+ name="nameserver_journal",
51
+ kwargs={"model": NameServer},
52
+ ),
53
+ path(
54
+ "nameservers/<int:pk>/changelog/",
55
+ ObjectChangeLogView.as_view(),
56
+ name="nameserver_changelog",
57
+ kwargs={"model": NameServer},
58
+ ),
59
+ path(
60
+ "nameservers/<int:pk>/zones/",
61
+ NameServerZoneListView.as_view(),
62
+ name="nameserver_zones",
63
+ ),
64
+ path(
65
+ "nameservers/<int:pk>/soazones/",
66
+ NameServerSOAZoneListView.as_view(),
67
+ name="nameserver_soa_zones",
68
+ ),
69
+ ]
@@ -0,0 +1,41 @@
1
+ from django.urls import path
2
+
3
+ from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
4
+
5
+ from netbox_dns.models import Record
6
+ from netbox_dns.views import (
7
+ RecordListView,
8
+ RecordView,
9
+ RecordEditView,
10
+ RecordDeleteView,
11
+ RecordBulkImportView,
12
+ RecordBulkEditView,
13
+ RecordBulkDeleteView,
14
+ ManagedRecordListView,
15
+ )
16
+
17
+ record_urlpatterns = [
18
+ path("records/", RecordListView.as_view(), name="record_list"),
19
+ path("records/add/", RecordEditView.as_view(), name="record_add"),
20
+ path("records/import/", RecordBulkImportView.as_view(), name="record_import"),
21
+ path("records/edit/", RecordBulkEditView.as_view(), name="record_bulk_edit"),
22
+ path("records/delete/", RecordBulkDeleteView.as_view(), name="record_bulk_delete"),
23
+ path("records/<int:pk>/", RecordView.as_view(), name="record"),
24
+ path("records/<int:pk>/edit/", RecordEditView.as_view(), name="record_edit"),
25
+ path("records/<int:pk>/delete/", RecordDeleteView.as_view(), name="record_delete"),
26
+ path(
27
+ "records/<int:pk>/journal/",
28
+ ObjectJournalView.as_view(),
29
+ name="record_journal",
30
+ kwargs={"model": Record},
31
+ ),
32
+ path(
33
+ "records/<int:pk>/changelog/",
34
+ ObjectChangeLogView.as_view(),
35
+ name="record_changelog",
36
+ kwargs={"model": Record},
37
+ ),
38
+ path(
39
+ "managedrecords/", ManagedRecordListView.as_view(), name="managed_record_list"
40
+ ),
41
+ ]