Skip to main content

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 dates
  • SoftwareVersion (per Platform)
  • SoftwareImageFile
  • DeviceSoftware — software actually running on a Device
  • InventoryItemSoftware — 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 it
  • ValidatedSoftware — approval rules
  • Contract
  • Provider
  • CVE
  • Vulnerability

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

  1. 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
    
  2. 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,
        },
    }
    
  3. Apply migrations:

    cd /opt/netbox/netbox   # your NetBox root
    python3 manage.py migrate
    

    The shipped 0001_initial migration was generated against NetBox v4.6.4. If your host runs a different NetBox version, run python3 manage.py makemigrations netbox_dlm first 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.

  4. Restart NetBox (systemctl restart netbox netbox-rq or your equivalent). You should see "Device Lifecycle" in the left nav, and Scripts under Operations > Scripts grouped by this plugin.

  5. 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:

  1. netbox-docker's base image doesn't ship third-party plugins, so you need a custom image. Add a plugin_requirements.txt next to your docker-compose.yml:

    netbox-dlm
    

    and a Dockerfile-Plugins (see netbox-docker's plugins documentation for the current template) that RUNs pip install -r /opt/netbox/plugin_requirements.txt on top of the base image. Point your compose file's build at it instead of pulling the stock image.

  2. Configure the plugin via netbox-docker's dedicated config file, /etc/netbox/config/plugins.py (typically mounted from configuration/plugins.py in your compose repo), rather than editing configuration.py directly:

    PLUGINS = ["netbox_dlm"]
    
    PLUGINS_CONFIG = {
        "netbox_dlm": {
            "nist_api_key": None,
            "eos_warning_days": 180,
        },
    }
    
  3. Rebuild and restart: docker compose build && docker compose up -d. netbox-docker runs migrate and collectstatic automatically on container startup, so no separate migration step is needed — just watch the netbox container's startup logs to confirm the migration applied cleanly.

  4. 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.devices M2M) or by Contract.platforms (any device on a covered platform). Unlike ValidatedSoftware, an empty scope covers nothing — covers_device() and covered_devices do the lookup, so a contract can't silently apply to devices nobody scoped it to.
  • Hardware Notices — one row per DeviceType or ModuleType (not both — enforced in clean()), with EoS/EoL/EoSecurity/EoSW dates.
  • Software Versions / Images — per Platform. SoftwareVersion.release_designation optionally 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). DeviceSoftware is a 1:1 to Device recording what's actually running (populate this from your existing sync tooling — e.g. alongside aci_netbox_sync runs, or a Golden Config compliance pass). InventoryItemSoftware is the same idea for a dcim.InventoryItem — useful for management controllers (Cisco CIMC, Dell iDRAC, HPE iLO, etc.) modeled as inventory items rather than as their own Device. Since InventoryItem has no platform field of its own, InventoryItemRolePlatform declares which Platform's SoftwareVersions apply to a given InventoryItemRole (e.g. "Management Controller" → a "Cisco CIMC" platform); once that mapping exists, the InventoryItemSoftware add form narrows its version picker to that platform, and clean() rejects a mismatched selection.
  • Validated Software — approval rules scoped by device_types, device_roles, specific devices, platforms, and/or inventory_item_roles (all M2M). A rule with no scope at all applies to any device or inventory item running that software version. preferred=True marks the target version for a given scope; covers_device()/covers_inventory_item() and valid_now do the compliance-check heavy lifting.
  • CVE / Vulnerability — CVE.affected_software M2M links a CVE to one or more SoftwareVersions; Vulnerability narrows that down to (optionally) a specific Device or InventoryItem (at most one of the two), with its own status workflow (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-valid ValidatedSoftware rule, 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 to services.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 NetBoxModel if you want a graphable history.
  • Inventory item hardware notices — InventoryItemSoftware and its ValidatedSoftware/Vulnerability scoping now cover InventoryItem, but HardwareNotice (EoS/EoL dates) is still scoped to DeviceType/ModuleType only. If you're using NetBox's legacy InventoryItem model for non-modular gear and want EoL tracking for it too, that's a straightforward additional FK to add to HardwareNotice.
  • VM software tracking — DeviceSoftware only covers Device, not VirtualMachine. Trivial to mirror if needed.
  • Automated CVE ingestion — SyncCVEs is 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)

Source distribution for netbox-dlm 0.10.2
File Size Uploaded
netbox_dlm-0.10.2.tar.gz 38.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for netbox-dlm 0.10.2
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.10.2 This release

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page