feat: IPAM-Bereiche automatisch ergänzen

Fehlende Prefixe können direkt aus der IPAM-Bereichsliste für alle sichtbaren IP-Adressen angelegt werden. Zusätzlich zeigt die Prefix-IP-Ansicht das zugewiesene Gerät oder die VM standardmäßig an.
This commit is contained in:
2026-07-23 11:15:58 +02:00
parent 65ea56f67e
commit acb4e449bc
9 changed files with 87 additions and 9 deletions
+4 -1
View File
@@ -4,6 +4,8 @@ Plugin für **NetBox 4.6.5** mit zwei Funktionen:
- Beim Speichern einer IP-Adresse wird das durch deren CIDR-Maske beschriebene Prefix gesucht und, falls es fehlt, automatisch erstellt. NetBox ordnet die IP danach nativ anhand von Prefix und VRF ein. - Beim Speichern einer IP-Adresse wird das durch deren CIDR-Maske beschriebene Prefix gesucht und, falls es fehlt, automatisch erstellt. NetBox ordnet die IP danach nativ anhand von Prefix und VRF ein.
- Eine zusätzliche IP-Netzübersicht kann nach Organisation/Region, Standortgruppe, Standort, Lokation, Mandantengruppe und Mandant gefiltert werden. - Eine zusätzliche IP-Netzübersicht kann nach Organisation/Region, Standortgruppe, Standort, Lokation, Mandantengruppe und Mandant gefiltert werden.
- Unter **IPAM → Prefixes/IP-Bereiche** legt die Aktion **Alle fehlenden Bereiche anlegen** die Netze für sämtliche bereits vorhandenen, sichtbaren IP-Adressen an.
- Unter **Prefix/IP-Bereich → IP-Adressen** wird das zugehörige Gerät beziehungsweise die VM standardmäßig als eigene Spalte angezeigt.
## Installation ## Installation
@@ -50,7 +52,8 @@ python /opt/netbox/netbox/manage.py reconcile_ip_prefixes
Für die Übersicht ist die NetBox-Berechtigung `ipam.view_prefix` erforderlich. Die automatische Erstellung läuft serverseitig; stellen Sie sicher, dass dies zu Ihrem Berechtigungs- und Change-Control-Konzept passt. Für die Übersicht ist die NetBox-Berechtigung `ipam.view_prefix` erforderlich. Die automatische Erstellung läuft serverseitig; stellen Sie sicher, dass dies zu Ihrem Berechtigungs- und Change-Control-Konzept passt.
Die Aktion für Bestandsdaten benötigt `ipam.view_ipaddress` und `ipam.add_prefix`. Sie verarbeitet nur IP-Adressen, die der ausführende Benutzer sehen darf.
## Hinweis zu „Organisation" ## Hinweis zu „Organisation"
NetBox besitzt kein separates Core-Modell namens Organisation. Die Übersicht bildet Organisation auf NetBox-`Region` ab und bezieht untergeordnete Regionen sowie deren Standorte und Lokationen ein. NetBox besitzt kein separates Core-Modell namens Organisation. Die Übersicht bildet Organisation auf NetBox-`Region` ab und bezieht untergeordnete Regionen sowie deren Standorte und Lokationen ein.
+1 -2
View File
@@ -1,5 +1,4 @@
from .config import BetterIPsConfig from .config import BetterIPsConfig
__version__ = "1.0.0" __version__ = "1.1.0"
config = BetterIPsConfig config = BetterIPsConfig
+2 -2
View File
@@ -6,7 +6,7 @@ class BetterIPsConfig(PluginConfig):
verbose_name = "NetBox Better IPs" verbose_name = "NetBox Better IPs"
description = "Automatische Prefix-Zuordnung und erweiterte IP-Netzübersicht" description = "Automatische Prefix-Zuordnung und erweiterte IP-Netzübersicht"
author = "LKE" author = "LKE"
version = "1.0.0" version = "1.1.0"
base_url = "better-ips" base_url = "better-ips"
min_version = "4.6.5" min_version = "4.6.5"
max_version = "4.6.99" max_version = "4.6.99"
@@ -21,4 +21,4 @@ class BetterIPsConfig(PluginConfig):
def ready(self): def ready(self):
super().ready() super().ready()
from . import signals # noqa: F401 from . import signals # noqa: F401
from . import tables # noqa: F401
+23
View File
@@ -0,0 +1,23 @@
import django_tables2 as tables
from ipam.tables import AnnotatedIPAddressTable
from utilities.tables import register_table_column
device_or_vm = tables.Column(
accessor="assigned_object__parent_object",
linkify=True,
orderable=False,
verbose_name="Gerät / VM",
empty_values=(),
)
register_table_column(device_or_vm, "device_or_vm", AnnotatedIPAddressTable)
# Registered columns are selectable but not displayed by default. The annotated
# table is used specifically by Prefix -> IP Addresses, where this information
# should be visible immediately.
if "device_or_vm" not in AnnotatedIPAddressTable.Meta.default_columns:
AnnotatedIPAddressTable.Meta.default_columns = (
*AnnotatedIPAddressTable.Meta.default_columns,
"device_or_vm",
)
+11
View File
@@ -0,0 +1,11 @@
from netbox.plugins import PluginTemplateExtension
class PrefixListActions(PluginTemplateExtension):
model = "ipam.prefix"
def list_buttons(self):
return self.render("netbox_better_ips/inc/prefix_list_buttons.html")
template_extensions = (PrefixListActions,)
@@ -0,0 +1,9 @@
{% if perms.ipam.view_ipaddress and perms.ipam.add_prefix %}
<form method="post" action="{% url 'plugins:netbox_better_ips:reconcile_missing_prefixes' %}" class="d-inline">
{% csrf_token %}
<button type="submit" class="btn btn-primary">
<i class="mdi mdi-auto-fix" aria-hidden="true"></i>
Alle fehlenden Bereiche anlegen
</button>
</form>
{% endif %}
+2 -2
View File
@@ -1,10 +1,10 @@
from django.urls import path from django.urls import path
from .views import NetworkOverviewView from .views import NetworkOverviewView, reconcile_missing_prefixes
app_name = "netbox_better_ips" app_name = "netbox_better_ips"
urlpatterns = [ urlpatterns = [
path("networks/", NetworkOverviewView.as_view(), name="network_overview"), path("networks/", NetworkOverviewView.as_view(), name="network_overview"),
path("reconcile/", reconcile_missing_prefixes, name="reconcile_missing_prefixes"),
] ]
+34 -1
View File
@@ -1,13 +1,18 @@
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db.models import Q from django.db.models import Q
from django.shortcuts import redirect
from django.views.decorators.http import require_POST
from django.views.generic import TemplateView from django.views.generic import TemplateView
from dcim.models import Location, Region, Site, SiteGroup from dcim.models import Location, Region, Site, SiteGroup
from ipam.models import Prefix from ipam.models import IPAddress, Prefix
import netaddr import netaddr
from .forms import NetworkOverviewFilterForm from .forms import NetworkOverviewFilterForm
from .services import ensure_prefix_for_ip
def _descendant_ids(obj): def _descendant_ids(obj):
@@ -87,3 +92,31 @@ class NetworkOverviewView(PermissionRequiredMixin, TemplateView):
} }
) )
return context return context
@require_POST
@permission_required(("ipam.view_ipaddress", "ipam.add_prefix"), raise_exception=True)
def reconcile_missing_prefixes(request):
created = skipped = failed = 0
addresses = IPAddress.objects.restrict(request.user, "view").select_related(
"tenant", "assigned_object_type"
)
for address in addresses.iterator():
try:
prefix, was_created = ensure_prefix_for_ip(address)
created += int(was_created)
skipped += int(prefix is None)
except Exception:
failed += 1
if failed:
messages.warning(
request,
f"{created} Bereiche wurden angelegt; {failed} IP-Adressen konnten nicht verarbeitet werden.",
)
else:
messages.success(
request,
f"{created} fehlende Bereiche wurden angelegt. {skipped} Host-Adressen wurden ignoriert.",
)
return redirect("ipam:prefix_list")
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "netbox-better-ips" name = "netbox-better-ips"
version = "1.0.0" version = "1.1.0"
description = "Automatic prefix creation and an organization-aware IP network overview for NetBox 4.6" description = "Automatic prefix creation and an organization-aware IP network overview for NetBox 4.6"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"