diff --git a/README.md b/README.md index 4e63282..7bfc55c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Plugin für **NetBox 4.6.5** mit zwei Funktionen: - Eine zusätzliche IP-Netzübersicht kann nach Organisation/Region, Standortgruppe, Standort, Lokation, Mandantengruppe und Mandant gefiltert werden. - Unter **IPAM → IP-Bereiche** legt die Aktion **Alle fehlenden Bereiche anlegen** die Bereiche für sämtliche bereits vorhandenen, sichtbaren IP-Adressen an. - Unter **IP-Bereich → IP-Adressen** wird das zugehörige Gerät beziehungsweise die VM standardmäßig als eigene Spalte angezeigt. +- Die **IP-Netzübersicht** ist als eigener Eintrag direkt im Menü **IPAM** verfügbar. ## Installation diff --git a/netbox_better_ips/__init__.py b/netbox_better_ips/__init__.py index 16e81ed..b930002 100644 --- a/netbox_better_ips/__init__.py +++ b/netbox_better_ips/__init__.py @@ -1,4 +1,4 @@ from .config import BetterIPsConfig -__version__ = "1.2.0" +__version__ = "1.2.1" config = BetterIPsConfig diff --git a/netbox_better_ips/config.py b/netbox_better_ips/config.py index 07dfdea..adb2402 100644 --- a/netbox_better_ips/config.py +++ b/netbox_better_ips/config.py @@ -6,7 +6,7 @@ class BetterIPsConfig(PluginConfig): verbose_name = "NetBox Better IPs" description = "Automatische Prefix-Zuordnung und erweiterte IP-Netzübersicht" author = "LKE" - version = "1.2.0" + version = "1.2.1" base_url = "better-ips" min_version = "4.6.5" max_version = "4.6.99" @@ -21,3 +21,6 @@ class BetterIPsConfig(PluginConfig): super().ready() from . import signals # noqa: F401 from . import tables # noqa: F401 + from .navigation import register_ipam_menu_item + + register_ipam_menu_item() diff --git a/netbox_better_ips/management/commands/reconcile_ip_prefixes.py b/netbox_better_ips/management/commands/reconcile_ip_prefixes.py index 1e87b44..5c26a5b 100644 --- a/netbox_better_ips/management/commands/reconcile_ip_prefixes.py +++ b/netbox_better_ips/management/commands/reconcile_ip_prefixes.py @@ -11,12 +11,17 @@ class Command(BaseCommand): parser.add_argument("--dry-run", action="store_true") def handle(self, *args, **options): - created = skipped = 0 + created = skipped = failed = 0 for address in IPAddress.objects.select_related("tenant", "assigned_object_type").iterator(): - ip_range, was_created = ensure_range_for_ip(address) - if options["dry_run"] and was_created: - ip_range.delete() - created += int(was_created) - skipped += int(ip_range is None) + try: + ip_range, was_created = ensure_range_for_ip(address) + if options["dry_run"] and was_created: + ip_range.delete() + created += int(was_created) + skipped += int(ip_range is None) + except Exception as exc: + failed += 1 + self.stderr.write(f"Fehler bei {address}: {exc}") verb = "würden erstellt" if options["dry_run"] else "erstellt" - self.stdout.write(self.style.SUCCESS(f"{created} IP-Bereiche {verb}; {skipped} Hostmasken ignoriert.")) + message = f"{created} IP-Bereiche {verb}; {skipped} Hostmasken ignoriert; {failed} Fehler." + self.stdout.write(self.style.SUCCESS(message) if not failed else self.style.WARNING(message)) diff --git a/netbox_better_ips/navigation.py b/netbox_better_ips/navigation.py index 27b1775..02e7f31 100644 --- a/netbox_better_ips/navigation.py +++ b/netbox_better_ips/navigation.py @@ -1,10 +1,25 @@ -from netbox.plugins import PluginMenuItem +from netbox.navigation import MenuItem -menu_items = ( - PluginMenuItem( - link="plugins:netbox_better_ips:network_overview", - link_text="IP-Netzübersicht", - permissions=["ipam.view_prefix"], - ), -) +# The public plugin navigation API can only create a separate Plugins menu. +# NetBox 4.6.5 does not expose an API for extending an existing core menu, so +# this pinned-version integration appends our entry to IPAM's first group. +def register_ipam_menu_item(): + from netbox.navigation.menu import IPAM_MENU + + group = IPAM_MENU.groups[0] + link = "plugins:netbox_better_ips:network_overview" + if any(item.link == link for item in group.items): + return + group.items = ( + *group.items, + MenuItem( + link=link, + link_text="IP-Netzübersicht", + permissions=["ipam.view_prefix"], + ), + ) + + +# Do not duplicate the entry in NetBox's generic Plugins menu. +menu_items = () diff --git a/netbox_better_ips/services.py b/netbox_better_ips/services.py index 450eb35..3426c84 100644 --- a/netbox_better_ips/services.py +++ b/netbox_better_ips/services.py @@ -1,6 +1,7 @@ import ipaddress import logging +import netaddr from django.db import transaction from ipam.models import IPRange from netbox.plugins import get_plugin_config @@ -46,8 +47,10 @@ def ensure_range_for_ip(ip, *, config=None): elif network.version == 6 and network.prefixlen < 127: first += 1 - start_address = f"{ipaddress.ip_address(first)}/{network.prefixlen}" - end_address = f"{ipaddress.ip_address(last)}/{network.prefixlen}" + # IPRange.save() performs arithmetic on the field values before Django's + # field conversion runs, so these must be netaddr objects rather than strings. + start_address = netaddr.IPNetwork(f"{ipaddress.ip_address(first)}/{network.prefixlen}") + end_address = netaddr.IPNetwork(f"{ipaddress.ip_address(last)}/{network.prefixlen}") lookup = { "start_address": start_address, "end_address": end_address, diff --git a/pyproject.toml b/pyproject.toml index ea58737..7ce5242 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "netbox-better-ips" -version = "1.2.0" +version = "1.2.1" description = "Automatic prefix creation and an organization-aware IP network overview for NetBox 4.6" readme = "README.md" requires-python = ">=3.12"