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:
@@ -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,5 +1,4 @@
|
|||||||
from .config import BetterIPsConfig
|
from .config import BetterIPsConfig
|
||||||
|
|
||||||
__version__ = "1.0.0"
|
__version__ = "1.1.0"
|
||||||
config = BetterIPsConfig
|
config = BetterIPsConfig
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
)
|
||||||
@@ -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 %}
|
||||||
@@ -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"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user