fix: skip patchpanel automation on edits

This commit is contained in:
2026-08-06 16:07:47 +02:00
parent 66d13292f2
commit 267a78d58d
5 changed files with 57 additions and 11 deletions
+6 -6
View File
@@ -35,7 +35,7 @@ Release-Tag oder ein bestimmter Commit verwendet werden:
```bash ```bash
/opt/netbox/venv/bin/pip install --upgrade --force-reinstall \ /opt/netbox/venv/bin/pip install --upgrade --force-reinstall \
"git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.7.3" "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.7.4"
``` ```
Alternativ kann hinter dem `@` die vollständige Commit-ID stehen. Alternativ kann hinter dem `@` die vollständige Commit-ID stehen.
@@ -142,15 +142,15 @@ weiter. Auch Kurzformen wie `F01` und `R1` werden als dieselbe Kennung erkannt.
Fehlt die passende Gegenseite, bleibt der Port unverknüpft; die nachfolgenden Fehlt die passende Gegenseite, bleibt der Port unverknüpft; die nachfolgenden
Nummern rutschen nicht auf. Nummern rutschen nicht auf.
Die Zuordnung wird nach Änderungen am Gerät, nach dem Einbau eines Moduls und Die Zuordnung wird ausschließlich beim erstmaligen Anlegen eines Patchpanels,
nach dem Anlegen oder Umbenennen einzelner Front- beziehungsweise Rearports beim Einbau eines neuen Moduls sowie beim Anlegen eines neuen Front- oder
erneut hergestellt. Dabei ersetzt die Patchpanel-Automatik abweichende Rearports hergestellt. Das Bearbeiten eines vorhandenen Patchpanels, Moduls
vorhandene Port-Mappings auf diesen Geräten durch die feste 1:1-Zuordnung. oder Ports löst die Automatik nicht aus.
Bei Installation oder Update findet kein automatischer Bestandslauf statt. Bei Installation oder Update findet kein automatischer Bestandslauf statt.
Vorhandene Patchpanel-Geräte und deren Kabelpfade bleiben unverändert. Die Vorhandene Patchpanel-Geräte und deren Kabelpfade bleiben unverändert. Die
Automatik greift erst, wenn ein betreffendes Gerät, Modul oder ein Front-/Rearport Automatik greift erst, wenn ein betreffendes Gerät, Modul oder ein Front-/Rearport
anschließend neu angelegt beziehungsweise gespeichert wird. neu angelegt wird.
### Mehrere Geräte mit NetBox Reorder Rack verschieben ### Mehrere Geräte mit NetBox Reorder Rack verschieben
+1 -1
View File
@@ -1,6 +1,6 @@
from netbox.plugins import PluginConfig, get_plugin_config from netbox.plugins import PluginConfig, get_plugin_config
__version__ = "0.7.3" __version__ = "0.7.4"
class NetBoxUtilitiesConfig(PluginConfig): class NetBoxUtilitiesConfig(PluginConfig):
+6 -2
View File
@@ -117,8 +117,8 @@ def synchronize_patchpanel(device_id):
return len(pairs) return len(pairs)
def _component_saved(sender, instance, raw=False, **kwargs): def _component_saved(sender, instance, created=False, raw=False, **kwargs):
if not raw and not _component_instantiation_active.get(): if created and not raw and not _component_instantiation_active.get():
synchronize_patchpanel(getattr(instance, "device_id", None)) synchronize_patchpanel(getattr(instance, "device_id", None))
@@ -131,6 +131,10 @@ def _wrap_component_container_save(model, device_id_getter):
@wraps(original_save) @wraps(original_save)
def patchpanel_aware_save(instance, *args, **kwargs): def patchpanel_aware_save(instance, *args, **kwargs):
created = instance._state.adding
if not created:
return original_save(instance, *args, **kwargs)
token = _component_instantiation_active.set(True) token = _component_instantiation_active.set(True)
try: try:
result = original_save(instance, *args, **kwargs) result = original_save(instance, *args, **kwargs)
+43 -1
View File
@@ -4,7 +4,14 @@ from unittest.mock import MagicMock, patch
from django.test import SimpleTestCase from django.test import SimpleTestCase
from netbox_utilities.patchpanel import is_patchpanel, pair_ports, port_identifier, retrace_patchpanel_paths from netbox_utilities.patchpanel import (
_component_saved,
_wrap_component_container_save,
is_patchpanel,
pair_ports,
port_identifier,
retrace_patchpanel_paths,
)
def port(pk, name): def port(pk, name):
@@ -12,6 +19,41 @@ def port(pk, name):
class PatchpanelPairingTest(SimpleTestCase): class PatchpanelPairingTest(SimpleTestCase):
@patch("netbox_utilities.patchpanel.synchronize_patchpanel")
def test_component_edits_do_not_trigger_automation(self, synchronize):
component = SimpleNamespace(device_id=42)
_component_saved(None, component, created=False)
synchronize.assert_not_called()
@patch("netbox_utilities.patchpanel.synchronize_patchpanel")
def test_new_components_trigger_automation(self, synchronize):
component = SimpleNamespace(device_id=42)
_component_saved(None, component, created=True)
synchronize.assert_called_once_with(42)
@patch("netbox_utilities.patchpanel.synchronize_patchpanel")
def test_existing_device_save_does_not_trigger_automation(self, synchronize):
class Container:
def __init__(self, adding):
self._state = SimpleNamespace(adding=adding)
self.pk = 42
def save(self):
self._state.adding = False
return "saved"
_wrap_component_container_save(Container, lambda instance: instance.pk)
self.assertEqual(Container(adding=False).save(), "saved")
synchronize.assert_not_called()
self.assertEqual(Container(adding=True).save(), "saved")
synchronize.assert_called_once_with(42)
def test_existing_device_migrations_are_noops(self): def test_existing_device_migrations_are_noops(self):
migration_names = ( migration_names = (
"0004_patchpanel_port_mappings", "0004_patchpanel_port_mappings",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "netbox-utilities" name = "netbox-utilities"
version = "0.7.3" version = "0.7.4"
description = "Navigation, tenant utilities, patchpanel mapping, bulk uploads, and atomic rack reordering for NetBox 4.6" description = "Navigation, tenant utilities, patchpanel mapping, bulk uploads, and atomic rack reordering for NetBox 4.6"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"