From 5c673d9903a5e1a0d67727078cc2287cef24d51c Mon Sep 17 00:00:00 2001 From: Sven Luthi Date: Mon, 21 Sep 2026 16:23:09 +0200 Subject: [PATCH] deleted: CHANGELOG.md Not really helpful. Just more work. Bye bye! modified: netbox_dns_bridge/__init__.py Bump version to 1.6.0-rc1 new file: netbox_dns_bridge/api/__init__.py new file: netbox_dns_bridge/api/serializers.py new file: netbox_dns_bridge/api/urls.py new file: netbox_dns_bridge/api/views.py Adds API to the plugin. In case someone needs it :P This fixes a serializer bug on Zone creation in the same stroke. --- CHANGELOG.md | 46 ---------- netbox_dns_bridge/__init__.py | 3 +- netbox_dns_bridge/api/__init__.py | 0 netbox_dns_bridge/api/serializers.py | 125 +++++++++++++++++++++++++++ netbox_dns_bridge/api/urls.py | 12 +++ netbox_dns_bridge/api/views.py | 46 ++++++++++ 6 files changed, 185 insertions(+), 47 deletions(-) delete mode 100644 CHANGELOG.md create mode 100644 netbox_dns_bridge/api/__init__.py create mode 100644 netbox_dns_bridge/api/serializers.py create mode 100644 netbox_dns_bridge/api/urls.py create mode 100644 netbox_dns_bridge/api/views.py diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 25321ad..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,46 +0,0 @@ -## Unreleased -- Move `notify_handler` from `signals/` to `jobs/` and rename to `notify`. -- Rename `SendClientDNSNotify` to `SendClientNotify`. It now sends a single NOTIFY - for the zone only; catalog zone entries (`catz`, `{view}.catz`) have been removed. -- Catalog zone NOTIFY is now scheduled by `increment_soa_serial` via - `schedule_catalog_zone_notify`, which enqueues `SendClientNotify` for `catz` and - `{view}.catz` — no separate job class needed. -- Extract a shared `_send_notify` helper used by both `SendClientNotify` and - `SendNSNotify` for message building and the send loop. -- Move all NOTIFY scheduling gates (`notify_clients`, `notify_ns_all_zones`, custom - field) into the scheduling functions. The signal handler calls the scheduling - functions unconditionally; each function decides whether to enqueue based on its - own settings gate. -- Replace the global `IntegerKeyValueSetting` model (single `catalog-zone-soa-serial` - value shared by all catalog zones) with a new `CatalogZone` model that has a 1:1 - foreign key to `netbox_dns.models.View` and its own `soa_serial` field. Each view's - catalog zone now tracks and increments its SOA serial independently. Existing serials - are preserved during migration by copying the old global value into every view's new - `CatalogZone` row. -- Change the `CatalogZoneMemberIdentifier.name` uniqueness from globally unique to - unique per catalog zone (`UniqueConstraint(name, catalog_zone)`). A `catalog_zone` - foreign key has been added to the identifier model to enforce this. -- Remove the `dns-settings` management command, which was a generic get/set/list - interface over `IntegerKeyValueSetting` (now removed). -- Defer the catalog zone SOA serial increment on zone deletion to `transaction.on_commit`, matching - the create/modify path. Previously the increment ran immediately at `post_delete` time, so a - rollback of the delete transaction would have left the catalog serial bumped anyway. -- Add the option to send a NOTIFY directly to a zone's own nameservers when its SOA serial number - changes. Enable it per zone via a boolean custom field named by `notify_ns_custom_field_name`, - globally for all zones via `notify_ns_all_zones` (default `False`), or both. Nameserver addresses - are resolved from NetBox DNS A/AAAA records within the zone's view and the NOTIFY is signed with - the per-view TSIG key. A companion `notify_ns_port` setting (default 53) controls the destination - port. - -## 1.0.7 - 2026-03-02 -README Change - Moving private keys to global scope since Bind 9.20 view scoped keys have become unreliable and sometimes wouldnt match. - -## 1.0.8 - 2026-03-12 -- Change License to MIT to match the netbox-plugin-dns License. This project rests on the netbox-plugin-dns so a matching - license makes more sense. -- Renaming Project from Netbox Plugin Bind Provisioner to Netbox DNS Bridge as new code will be contributed that allows - data to flow in both directions (Dynamic Updates), not just out of Netbox DNS. - -## 1.5.0 - 2026-04-08 -- Change to versioning scheme - Now matches the major and minor version number to the one of netbox-plugin-dns. Only the minor sub version - will be used to track incremental changes to this plugin. diff --git a/netbox_dns_bridge/__init__.py b/netbox_dns_bridge/__init__.py index 125bfe3..f965cb9 100644 --- a/netbox_dns_bridge/__init__.py +++ b/netbox_dns_bridge/__init__.py @@ -1,7 +1,8 @@ from netbox.plugins import PluginConfig from django.conf import settings -__version__ = "1.5.9-beta" +__version__ = "1.6.0-rc1" + class DNSBridgeConfig(PluginConfig): name = "netbox_dns_bridge" diff --git a/netbox_dns_bridge/api/__init__.py b/netbox_dns_bridge/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netbox_dns_bridge/api/serializers.py b/netbox_dns_bridge/api/serializers.py new file mode 100644 index 0000000..12d5757 --- /dev/null +++ b/netbox_dns_bridge/api/serializers.py @@ -0,0 +1,125 @@ +from rest_framework import serializers + +from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer + +import netbox_dns.models +from netbox_dns.api.nested_serializers import NestedZoneSerializer + +from netbox_dns_bridge.models import CatalogZone, CatalogZoneMember, SeenTransferClient + +__all__ = ( + "CatalogZoneSerializer", + "CatalogZoneMemberSerializer", + "SeenTransferClientSerializer", + "NestedCatalogZoneSerializer", + "NestedCatalogZoneMemberSerializer", +) + + +class NestedViewSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns-api:view-detail" + ) + + class Meta: + model = netbox_dns.models.View + fields = ("id", "url", "display", "name") + brief_fields = ("id", "url", "display", "name") + + +class NestedCatalogZoneSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns_bridge-api:catalogzone-detail" + ) + + class Meta: + model = CatalogZone + fields = ("id", "url", "display", "view", "soa_serial") + brief_fields = ("id", "url", "display", "view", "soa_serial") + + +class NestedCatalogZoneMemberSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns_bridge-api:catalogzonemember-detail" + ) + + class Meta: + model = CatalogZoneMember + fields = ("id", "url", "display", "name", "zone", "catalog_zone") + brief_fields = ("id", "url", "display", "name", "zone", "catalog_zone") + + +class CatalogZoneSerializer(NetBoxModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns_bridge-api:catalogzone-detail" + ) + view = NestedViewSerializer() + + class Meta: + model = CatalogZone + fields = ( + "id", + "url", + "display", + "display_url", + "view", + "soa_serial", + "soa_refresh", + "soa_retry", + "soa_expire", + "soa_minimum", + "created", + "last_updated", + "tags", + "custom_fields", + ) + brief_fields = ("id", "url", "display", "view", "soa_serial") + + +class CatalogZoneMemberSerializer(NetBoxModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns_bridge-api:catalogzonemember-detail" + ) + zone = NestedZoneSerializer() + catalog_zone = NestedCatalogZoneSerializer() + + class Meta: + model = CatalogZoneMember + fields = ( + "id", + "url", + "display", + "display_url", + "name", + "zone", + "catalog_zone", + "created", + "last_updated", + "tags", + "custom_fields", + ) + brief_fields = ("id", "url", "display", "name", "zone", "catalog_zone") + + +class SeenTransferClientSerializer(NetBoxModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name="plugins-api:netbox_dns_bridge-api:seentransferclient-detail" + ) + view = NestedViewSerializer() + + class Meta: + model = SeenTransferClient + fields = ( + "id", + "url", + "display", + "display_url", + "source_ip", + "last_seen", + "view", + "created", + "last_updated", + "tags", + "custom_fields", + ) + brief_fields = ("id", "url", "display", "source_ip", "last_seen", "view") diff --git a/netbox_dns_bridge/api/urls.py b/netbox_dns_bridge/api/urls.py new file mode 100644 index 0000000..eb9479e --- /dev/null +++ b/netbox_dns_bridge/api/urls.py @@ -0,0 +1,12 @@ +from netbox.api.routers import NetBoxRouter + +from . import views + +router = NetBoxRouter() +router.APIRootView = views.NetBoxDNSBridgeRootView + +router.register("catalog-zones", views.CatalogZoneViewSet) +router.register("catalog-zone-members", views.CatalogZoneMemberViewSet) +router.register("seen-transfer-clients", views.SeenTransferClientViewSet) + +urlpatterns = router.urls diff --git a/netbox_dns_bridge/api/views.py b/netbox_dns_bridge/api/views.py new file mode 100644 index 0000000..41b873f --- /dev/null +++ b/netbox_dns_bridge/api/views.py @@ -0,0 +1,46 @@ +from rest_framework.routers import APIRootView + +from netbox.api.viewsets import NetBoxModelViewSet + +from netbox_dns_bridge.filtersets import ( + CatalogZoneFilterSet, + CatalogZoneMemberFilterSet, + SeenTransferClientFilterSet, +) +from netbox_dns_bridge.models import CatalogZone, CatalogZoneMember, SeenTransferClient + +from .serializers import ( + CatalogZoneSerializer, + CatalogZoneMemberSerializer, + SeenTransferClientSerializer, +) + +__all__ = ( + "NetBoxDNSBridgeRootView", + "CatalogZoneViewSet", + "CatalogZoneMemberViewSet", + "SeenTransferClientViewSet", +) + + +class NetBoxDNSBridgeRootView(APIRootView): + def get_view_name(self): + return "NetBoxDNSBridge" + + +class CatalogZoneViewSet(NetBoxModelViewSet): + queryset = CatalogZone.objects.all() + serializer_class = CatalogZoneSerializer + filterset_class = CatalogZoneFilterSet + + +class CatalogZoneMemberViewSet(NetBoxModelViewSet): + queryset = CatalogZoneMember.objects.all() + serializer_class = CatalogZoneMemberSerializer + filterset_class = CatalogZoneMemberFilterSet + + +class SeenTransferClientViewSet(NetBoxModelViewSet): + queryset = SeenTransferClient.objects.all() + serializer_class = SeenTransferClientSerializer + filterset_class = SeenTransferClientFilterSet