netbox-dlm
A NetBox plugin for hardware/software lifecycle management — built as a real NetBox plugin (Django models, not Custom Objects), since this needs background scripts, custom filtersets/API viewsets, and many-to-many scoping that Custom Objects doesn't support well.
What it models
HardwareNotice(DeviceType or ModuleType) — EoS/EoL/EoSecurity/EoSW datesSoftwareVersion(per Platform)SoftwareImageFileDeviceSoftware— software actually running on a DeviceInventoryItemSoftware— software actually running on an InventoryItem (e.g. a Cisco CIMC or Dell iDRAC modeled as a legacy InventoryItem)InventoryItemRolePlatform— maps an InventoryItemRole to the Platform whose SoftwareVersions apply to itValidatedSoftware— approval rulesContractProviderCVEVulnerability
NetBox doesn't have native SoftwareVersion/Contact core models for
this, so those are built from scratch here rather than reused.
Reports are handled as on-demand Scripts (scripts.py) rather than
stored "*Result" models — CheckHardwareNotices and RunSoftwareValidation
compute compliance live against current data. This is a deliberate scope
simplification; add stored result models later as ordinary NetBoxModels
if you want historical trending of compliance over time.
Package layout
netbox_dlm/
├── __init__.py # PluginConfig
├── models.py # Provider, Contract, HardwareNotice, SoftwareVersion,
│ # SoftwareImageFile, DeviceSoftware, InventoryItemSoftware,
│ # InventoryItemRolePlatform, ValidatedSoftware,
│ # CVE, Vulnerability
├── choices.py # ChoiceSets
├── admin.py # Django admin registrations
├── forms.py # NetBoxModelForm / FilterSetForm classes
├── tables.py # NetBoxTable classes
├── filtersets.py # NetBoxModelFilterSet classes
├── views.py # Generic CRUD views
├── urls.py # UI URL routing
├── navigation.py # Nav menu ("Device Lifecycle")
├── template_content.py # Panels injected onto Device/DeviceType pages
├── scripts.py # CheckHardwareNotices, RunSoftwareValidation, SyncCVEs
├── templates/netbox_dlm/
│ ├── device_lifecycle_panel.html
│ ├── inventoryitem_lifecycle_panel.html
│ └── devicetype_lifecycle_panel.html
├── api/
│ ├── serializers.py
│ ├── views.py
│ └── urls.py
└── migrations/
├── __init__.py
└── 0001_initial.py # generated against NetBox v4.6.4 (see below)
Installation
-
Install the package into the same Python environment as NetBox — from PyPI:
pip install netbox-dlm
or, for local development, editable from a checkout via the included
pyproject.toml:pip install -e /path/to/netbox_dlm
-
Add to
configuration.py:PLUGINS = [ "netbox_dlm", # ... your other plugins ] PLUGINS_CONFIG = { "netbox_dlm": { "nist_api_key": None, # optional, raises NVD API rate limits "eos_warning_days": 180, }, }
-
Apply migrations:
cd /opt/netbox/netbox # your NetBox root python3 manage.py migrate
The shipped
0001_initialmigration was generated against NetBox v4.6.4. If your host runs a different NetBox version, runpython3 manage.py makemigrations netbox_dlmfirst and check the output for unexpected diffs before migrating — field/constraint behavior on NetBox's core models (dcim.Device,dcim.Platform, etc.) can shift between versions. -
Restart NetBox (
systemctl restart netbox netbox-rqor your equivalent). You should see "Device Lifecycle" in the left nav, and Scripts under Operations > Scripts grouped by this plugin. -
If you're serving static files separately behind a reverse proxy, run
python manage.py collectstatic --no-input.
Docker (netbox-docker)
Nothing about this plugin is Docker-incompatible — it's pure Python (only
dependency is requests, which NetBox core already pulls in), has no
compiled extensions, and doesn't use FileField/ImageField anywhere, so
it doesn't care whether media storage is local disk or S3. The steps just
differ from the bare-metal instructions above because of how
netbox-docker itself
works, not because of anything specific to this plugin:
-
netbox-docker's base image doesn't ship third-party plugins, so you need a custom image. Add aplugin_requirements.txtnext to yourdocker-compose.yml:netbox-dlmand a
Dockerfile-Plugins(see netbox-docker's plugins documentation for the current template) thatRUNspip install -r /opt/netbox/plugin_requirements.txton top of the base image. Point your compose file'sbuildat it instead of pulling the stock image. -
Configure the plugin via netbox-docker's dedicated config file,
/etc/netbox/config/plugins.py(typically mounted fromconfiguration/plugins.pyin your compose repo), rather than editingconfiguration.pydirectly:PLUGINS = ["netbox_dlm"] PLUGINS_CONFIG = { "netbox_dlm": { "nist_api_key": None, "eos_warning_days": 180, }, }
-
Rebuild and restart:
docker compose build && docker compose up -d. netbox-docker runsmigrateandcollectstaticautomatically on container startup, so no separate migration step is needed — just watch thenetboxcontainer's startup logs to confirm the migration applied cleanly. -
The same version-match caveat from step 3 above still applies: check that the NetBox image tag you're pinned to is compatible with the shipped migrations before rolling this out to a production stack.
Using it
- Providers / Contracts — track who supports what, and which devices a
contract covers, either explicitly (
Contract.devicesM2M) or byContract.platforms(any device on a covered platform). UnlikeValidatedSoftware, an empty scope covers nothing —covers_device()andcovered_devicesdo the lookup, so a contract can't silently apply to devices nobody scoped it to. - Hardware Notices — one row per
DeviceTypeorModuleType(not both — enforced inclean()), with EoS/EoL/EoSecurity/EoSW dates. - Software Versions / Images — per
Platform.SoftwareVersion.release_designationoptionally marks a version as N-1/N/N+1 in that platform's release train (at most one version per platform per designation, enforced by a DB constraint).DeviceSoftwareis a 1:1 toDevicerecording what's actually running (populate this from your existing sync tooling — e.g. alongsideaci_netbox_syncruns, or a Golden Config compliance pass).InventoryItemSoftwareis the same idea for adcim.InventoryItem— useful for management controllers (Cisco CIMC, Dell iDRAC, HPE iLO, etc.) modeled as inventory items rather than as their ownDevice. SinceInventoryItemhas noplatformfield of its own,InventoryItemRolePlatformdeclares whichPlatform'sSoftwareVersions apply to a givenInventoryItemRole(e.g. "Management Controller" → a "Cisco CIMC" platform); once that mapping exists, theInventoryItemSoftwareadd form narrows its version picker to that platform, andclean()rejects a mismatched selection. - Validated Software — approval rules scoped by
device_types,device_roles, specificdevices,platforms, and/orinventory_item_roles(all M2M). A rule with no scope at all applies to any device or inventory item running that software version.preferred=Truemarks the target version for a given scope;covers_device()/covers_inventory_item()andvalid_nowdo the compliance-check heavy lifting. - CVE / Vulnerability —
CVE.affected_softwareM2M links a CVE to one or moreSoftwareVersions;Vulnerabilitynarrows that down to (optionally) a specificDeviceorInventoryItem(at most one of the two), with its ownstatusworkflow (open → mitigated/resolved). - Scripts (Operations > Scripts > Device Lifecycle Management):
Check Hardware Notices— flags past-due and upcoming EoS.Run Software Validation— flags devices and inventory items whose recorded software has no currently-validValidatedSoftwarerule, or isn't the preferred version.Sync CVEs from NIST NVD— placeholder; wire up the actual NVD API 2.0 HTTP calls once your NetBox host has outbound access toservices.nvd.nist.gov.
Device, InventoryItem, and DeviceType pages get a right-hand panel (via
template_content.py) summarizing running software, compliance status, and
open vulnerabilities at a glance (the Device panel also shows the
HardwareNotice for its DeviceType, since hardware EoL notices are still
DeviceType/ModuleType-scoped only — see below).
Testing
./scripts/test-templates.sh
First run clones netbox-community/netbox (pinned to the version this
plugin targets) and builds a venv under .dev/ (gitignored, ~150MB);
subsequent runs reuse it. It compiles every template in
netbox_dlm/templates/netbox_dlm/ through NetBox's real template engine —
no database or Redis needed, since template compilation never touches the
ORM. This catches TemplateSyntaxError/TemplateDoesNotExist (bad
{% load %}, filters used where a tag was needed, missing includes)
before they reach a deployed host. It won't catch bugs that only manifest
at render time against real data (e.g. a table column referencing a model
attribute that silently resolves to nothing) — there's no substitute for
exercising the view against a real NetBox + Postgres instance for that.
What I didn't build (scope cuts, worth knowing about)
- Stored compliance-result models / history — this plugin computes
compliance live via scripts rather than persisting result rows.
Straightforward to add later as another
NetBoxModelif you want a graphable history. - Inventory item hardware notices —
InventoryItemSoftwareand itsValidatedSoftware/Vulnerabilityscoping now coverInventoryItem, butHardwareNotice(EoS/EoL dates) is still scoped toDeviceType/ModuleTypeonly. If you're using NetBox's legacyInventoryItemmodel for non-modular gear and want EoL tracking for it too, that's a straightforward additional FK to add toHardwareNotice. - VM software tracking —
DeviceSoftwareonly coversDevice, notVirtualMachine. Trivial to mirror if needed. - Automated CVE ingestion —
SyncCVEsis a stub; NVD API 2.0 request/response handling needs to be written against whatever auth/rate-limit setup you use.
Metadata
Release files for netbox-dlm 0.10.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| netbox_dlm-0.10.2.tar.gz | 38.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| netbox_dlm-0.10.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.4 kB
Release files / netbox_dlm-0.10.2.tar.gz
| Download URL | netbox_dlm-0.10.2.tar.gz |
|---|---|
| Size | 38.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
56a0df11ae8841b6764eddd77a7b4433062e290b45aea67294c314648abdc1ad
|
|
BLAKE2b-256 checksum How to use checksums |
c112933bc1bc3ba122d62223964743746c9ecc292736384d83ad8a54d621896e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / netbox_dlm-0.10.2-py3-none-any.whl
| Download URL | netbox_dlm-0.10.2-py3-none-any.whl |
|---|---|
| Size | 49.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
15ab8c045fe9098951d8ff147ed5993c7e91462360228f5d6e2967d8d0733558
|
|
BLAKE2b-256 checksum How to use checksums |
35530c53ea2a493aa6eceed27314760a062c8d491c36a96ecc84cb91897e1d93
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency log