Coverage for netbox_interface_name_rules / signals.py: 90.70%
39 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-16 10:13 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-16 10:13 +0000
1# SPDX-License-Identifier: Apache-2.0
2# Copyright (C) 2025 Marcin Zieba <marcinpsk@gmail.com>
3"""Django receivers: module, module bay and device saves go to the rename-trigger lifecycle with their alias.
5The receivers do not read ``raw``: a raw save, such as a fixture load, is a rename trigger too.
6"""
8import logging
10from django.db.models.signals import post_save, pre_save
11from django.dispatch import receiver
13from . import rename_triggers
15logger = logging.getLogger("netbox_interface_name_rules")
17# No Interface receiver: NetBox creates module interfaces with bulk_create(), so pre_save never runs.
20@receiver(pre_save, sender="dcim.Module", dispatch_uid="interface_name_rules_pre_save_module")
21def on_module_pre_save(sender, instance, using, **kwargs):
22 """Pass a module save to the rename-trigger lifecycle before the row is written."""
23 rename_triggers.before_save(sender, instance, using)
26@receiver(post_save, sender="dcim.Module", dispatch_uid="interface_name_rules_post_save_module")
27def on_module_saved(sender, instance, created, using, **kwargs):
28 """Pass a module save to the rename-trigger lifecycle after the row is written."""
29 rename_triggers.after_save(sender, instance, created, using)
32@receiver(pre_save, sender="dcim.ModuleBay", dispatch_uid="interface_name_rules_pre_save_module_bay")
33def on_module_bay_pre_save(sender, instance, using, **kwargs):
34 """Pass a module bay save to the rename-trigger lifecycle before the row is written."""
35 rename_triggers.before_save(sender, instance, using)
38@receiver(post_save, sender="dcim.ModuleBay", dispatch_uid="interface_name_rules_post_save_module_bay")
39def on_module_bay_saved(sender, instance, created, using, **kwargs):
40 """Pass a module bay save to the rename-trigger lifecycle after the row is written."""
41 rename_triggers.after_save(sender, instance, created, using)
44@receiver(pre_save, sender="dcim.Device", dispatch_uid="interface_name_rules_pre_save_device")
45def on_device_pre_save(sender, instance, using, **kwargs):
46 """Pass a device save to the rename-trigger lifecycle before the row is written."""
47 rename_triggers.before_save(sender, instance, using)
50@receiver(post_save, sender="dcim.Device", dispatch_uid="interface_name_rules_post_save_device")
51def on_device_saved(sender, instance, created, using, **kwargs):
52 """Pass a device save to the rename-trigger lifecycle after the row is written."""
53 rename_triggers.after_save(sender, instance, created, using)
56# ---------------------------------------------------------------------------
57# Cross-plugin integration: netbox-librenms-plugin name prediction
58# ---------------------------------------------------------------------------
59# When netbox-librenms-plugin is installed it exposes a Signal that asks
60# subscribers to rewrite the list of interface names it predicts a module's
61# templates will produce. Without this rewrite, its module-adoption lookup
62# would only see NetBox's raw template output and miss interfaces we renamed
63# after install. The import is guarded so INR works fine when librenms-plugin
64# is absent.
66try:
67 from netbox_librenms_plugin.signals import (
68 predict_module_interface_names as _librenms_predict_signal,
69 )
70except ImportError:
71 _librenms_predict_signal = None
74def on_librenms_predict_module_interface_names(sender, device, module, names, **kwargs):
75 """Rewrite librenms-plugin's predicted template names through our rule engine.
77 Always defined so it can be imported and tested in isolation even when
78 netbox-librenms-plugin is not installed. Signal registration is guarded
79 below so it only connects when the signal actually exists.
80 """
81 module_bay = getattr(module, "module_bay", None)
82 if module_bay is None: 82 ↛ 83line 82 didn't jump to line 83 because the condition on line 82 was never true
83 return None
84 try:
85 from .engine import predict_rule_output
87 return predict_rule_output(module, module_bay, names)
88 except Exception:
89 logger.exception(
90 "predict_rule_output failed for module pk=%s; leaving names unchanged",
91 getattr(module, "pk", "?"),
92 )
93 return None
96if _librenms_predict_signal is not None: 96 ↛ 97line 96 didn't jump to line 97 because the condition on line 96 was never true
97 receiver(
98 _librenms_predict_signal,
99 dispatch_uid="interface_name_rules_predict_module_interface_names",
100 )(on_librenms_predict_module_interface_names)