NetBox iDRAC Inventory Plugin
A NetBox plugin that synchronizes Dell PowerEdge server hardware inventory into NetBox by querying each server's iDRAC management interface via the Redfish API.
Features
- One-to-one Dell server record linked to a NetBox Device. Adding a Dell server creates the Device for you (its name defaults to the host part of the iDRAC FQDN); the record stores the iDRAC address, service tag, BIOS version and iDRAC firmware. The device type is set from the iDRAC-reported model on the first sync.
- Hardware component inventory — CPUs, DIMMs, disks, storage controllers
and power supplies are discovered and stored as
DellComponentobjects. - Health status — the iDRAC
Status.Healthof the server (rolled up) and of each component is mapped to a coloredhealthbadge (OK / Warning / Critical), so a failed PSU or disk is visible at a glance and filterable. - iDRAC management IP — the iDRAC's own NIC is modelled as a mgmt-only
iDRACinterface (with its MAC), the iDRAC IPv4 is created in IPAM and set as the device's out-of-band IP (oob_ip). - Native network modelling — each physical network adapter is created as a
NetBox
Module(with a matchingModuleType) installed in aModuleBayon the device, and each physical port becomes anInterfacewith its MAC address and link speed. Ports are matched to an existing interface by MAC address first, falling back to name — so a device that already had interfaces before being onboarded (under whatever names/cables were there previously) gets reconciled onto its real Dell port name in place, rather than getting a duplicate interface. The NUMA node the adapter's PCIe lanes are wired to (from Dell'sCPUAffinity, converted from Dell's 1-indexed CPU socket to a 0-indexed NUMA node) is stored in thenuma_nodecustom field on theModuleBay. - LLDP discovery — the LLDP neighbour reported by iDRAC for each connected
port (remote switch + remote port) is stored in the
lldp_remote_chassisandlldp_remote_portcustom fields on the interface. These, andnuma_node, are created automatically on first migrate. - Firmware inventory — the Redfish
UpdateService/FirmwareInventoryis read on each sync and the installed version is written to matching components (by FQDD), covering parts whose own resource omits a version. - Sync-on-demand — trigger a sync from the NetBox UI (single server or a
bulk Sync from iDRAC action on the server list) or via the REST API
(
POST .../servers/<id>/sync/); sync runs as a background job. - Scheduled sync — set
sync_interval_minutes> 0 to register a recurring system job that fans out one sync job per Dell server, so the RQ workers run them in parallel and one unreachable iDRAC never stalls the fleet. - Network discovery — define a Scan Range (CIDR / range / hosts); a discovery job probes each iDRAC and imports it, attaching to an existing device with the same service tag when one exists (no duplicate) or creating a new one. New devices get the range's site as a default and are flagged on the Site Review page so it can be confirmed or corrected per device — handy when one iDRAC subnet spans several sites.
- Full REST API at
/api/plugins/idrac-inventory/(servers + components). - GraphQL queries
dell_server/dell_server_list/dell_component/dell_component_listexposed through NetBox's Strawberry schema. - Credentials — a global iDRAC password comes from
PLUGINS_CONFIG/ environment; an optional per-device password (when machines differ) is stored encrypted at rest (Fernet, keyed on NetBoxSECRET_KEY) and is never returned by the API.
Compatibility
| Plugin version | NetBox version |
|---|---|
| 0.2.x | 4.1 – 4.6 |
| 0.1.x | 4.1 or later |
NetBox 4.6+ requires API_TOKEN_PEPPERS in your NetBox configuration (a
core NetBox requirement, not a plugin one).
Requires Python 3.10+.
Installation
1. Install the package
pip install netbox-idrac-inventory
2. Add to configuration.py
PLUGINS = [
"netbox_idrac_inventory",
]
PLUGINS_CONFIG = {
"netbox_idrac_inventory": {
# iDRAC credentials used when a DellServer has no per-device username set.
"idrac_default_username": "root",
# Prefer setting the password via an environment variable rather than
# committing it to the config file. The plugin checks the env var
# IDRAC_DEFAULT_PASSWORD before falling back to this value.
"idrac_default_password": "",
# Set to True (and provide a valid CA bundle) in production.
"idrac_verify_ssl": False,
# HTTP request timeout in seconds for iDRAC Redfish calls.
"idrac_timeout": 30,
# When True, the sync writes the iDRAC service tag to Device.serial
# in NetBox so the physical device record stays up to date.
"update_device_serial": True,
# When True, the sync creates a mgmt-only "iDRAC" interface with the
# iDRAC IP and sets it as the device's out-of-band IP.
"manage_idrac_interface": True,
# Minutes between automatic syncs of every Dell server (0 = disabled,
# sync stays manual). Read at worker startup — restart the RQ worker
# after changing it.
"sync_interval_minutes": 0,
# Optional list of prefixes that iDRAC addresses and scan targets
# must fall within, e.g. ["10.116.0.0/16"]. Empty = no restriction.
# Strongly recommended: see "Credentials and security" below.
"allowed_networks": [],
}
}
3. Apply database migrations
python manage.py migrate
Usage
Add a Dell server
Two ways:
- From scratch — go to Plugins → iDRAC Inventory → Dell Servers → Add.
Enter the iDRAC address, a device name (left blank, it defaults to the
host part of the iDRAC FQDN, e.g.
host01.ipmi.example.com→host01), a site and a role. The plugin creates the Device (with a placeholder device type, replaced by the real model on the first sync) and links it. - From an existing device — on a Device page, use the iDRAC Inventory panel's Add button; the new record is attached to that device instead of creating a new one. If the device already has an interface named "iDRAC" with an IP assigned (common for a device onboarded before this plugin, already cabled and documented), the iDRAC address field is pre-filled from it.
Optionally set a per-device iDRAC username; otherwise the plugin default is used.
Trigger a sync
-
UI: open the DellServer (or its Device) page and click Sync from iDRAC. The sync runs as a NetBox background job; refresh to see the result in
sync_status/sync_message. -
REST API:
curl -X POST \ -H "Authorization: Token <your-token>" \ https://netbox.example.com/api/plugins/idrac-inventory/servers/42/sync/
Returns
HTTP 202with the background job ID:{ "job_id": 123, "job_url": "https://netbox.example.com/api/core/jobs/123/", "message": "Sync job enqueued for my-server-01 (SVC00042)." }
Triggering a sync requires the change permission on Dell servers (on top of NetBox's standard POST-to-add API permission mapping).
Discover servers from a range
Under Plugins → iDRAC Inventory → Scan Ranges → Add, define one or more
targets (one per line or comma-separated): a CIDR (10.0.0.0/24), a range
(10.0.0.10-20) or single hosts, plus the site and role for created devices.
Click Run scan (or POST .../scan-ranges/<id>/run/). For each reachable
iDRAC the discovery attaches to an existing device with the same service tag
(its site is left unchanged), or creates one, then syncs it.
Newly-created devices land with the range's site as a best-effort default only — useful when one iDRAC management subnet spans several NetBox sites and a single range can't be right for every host. Each such device is flagged for review; go to Plugins → iDRAC Inventory → Dell Servers → Site Review to confirm or correct the site per device.
REST API overview
Base path: /api/plugins/idrac-inventory/
| Method | Endpoint | Description |
|---|---|---|
| GET | /servers/ |
List all Dell servers |
| POST | /servers/ |
Create a Dell server record |
| GET | /servers/<id>/ |
Retrieve a Dell server |
| PATCH | /servers/<id>/ |
Update a Dell server |
| DELETE | /servers/<id>/ |
Delete a Dell server |
| POST | /servers/<id>/sync/ |
Enqueue an iDRAC sync job |
| GET | /components/ |
List all components |
| GET | /components/<id>/ |
Retrieve a component |
| GET/POST | /scan-ranges/ |
List / create scan ranges |
| POST | /scan-ranges/<id>/run/ |
Enqueue a discovery job |
The per-device / per-range idrac_password can be set via POST/PATCH; it
is write-only (encrypted before storage, never present in any response) and a
blank or absent value keeps the stored one.
Full OpenAPI schema is available at /api/schema/ in your NetBox instance.
GraphQL
query {
dell_server_list {
id
service_tag
model
sync_status
device { name }
}
}
query {
dell_server(id: 42) {
bios_version
idrac_firmware
last_synced
}
}
Credentials and security
- At sync time the plugin resolves the password in this order:
- The per-device
idrac_password(or a scan range's), when set. - Environment variable
IDRAC_DEFAULT_PASSWORD(recommended default for production — set it in your process manager / secrets manager). PLUGINS_CONFIG["netbox_idrac_inventory"]["idrac_default_password"].
- The per-device
- Per-device password — when servers don't share one password, set it on
the DellServer (or scan range). It is encrypted at rest with a key
derived from NetBox's
SECRET_KEY(Fernet), is write-only in the form and the API, and is never returned by the REST or GraphQL API. If you only have one shared password, leave these blank and use the global default above. SECRET_KEYrotation — rotate per Django's documented procedure (put the old key inSECRET_KEY_FALLBACKS) and stored passwords keep working. If a stored password can no longer be decrypted, the sync fails with a clear message instead of silently retrying with the global default (which could trip the iDRAC's account lockout); re-enter the password to recover.- The per-device
idrac_usernameoverridesidrac_default_usernamelikewise. - In production, set
idrac_verify_ssl: trueand provide a trusted CA bundle so TLS certificates are validated.
Restricting where syncs may connect
Anyone with change permission on Dell servers or scan ranges chooses which address the plugin connects to — and the sync presents the configured iDRAC credentials to that address. A malicious or compromised account could point a record at a host it controls and capture the global default password. To contain this:
- set
allowed_networksto the management prefixes your iDRACs live in; syncs and scans to any address (or DNS name resolving) outside them are refused; - grant
change_dellserver/change_dellscanrangesparingly, like any credential-bearing automation; - enable
idrac_verify_sslso credentials are never sent over unverified TLS.
Development
Quick start with Docker
A self-contained NetBox stack (NetBox + worker + Postgres + Redis) with the
plugin pre-installed lives under dev/. See dev/README.md:
cd dev
cp .env.example .env # set IDRAC_USERNAME / IDRAC_PASSWORD
docker compose up --build # NetBox at http://localhost:8000 (admin / admin)
Migrations
The plugin ships its schema migration (migrations/0001_initial.py), so a
plain python manage.py migrate is all that is needed. The LLDP custom fields
on dcim.Interface are not a migration — they are created idempotently by
a post_migrate signal (see signals.py) so they stay correct across NetBox
versions. If you change the models, regenerate with
python manage.py makemigrations netbox_idrac_inventory and commit the result.
Running tests
Tests must run inside the NetBox Django environment:
# From the NetBox source root with the plugin installed:
python manage.py test netbox_idrac_inventory
# or, with the dev stack running:
docker compose exec netbox \
/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py test netbox_idrac_inventory
Project layout
netbox_idrac_inventory/
api/
serializers.py # NetBoxModelSerializer subclasses
views.py # NetBoxModelViewSet subclasses + sync action
urls.py # NetBoxRouter registration
graphql/
types.py # Strawberry-django type definitions
schema.py # Root query class + schema list
idrac/
client.py # IdracClient — Redfish wrapper (sushy), plain dicts
sync.py # sync_server() — iDRAC -> NetBox reconcile logic
discovery.py # discover_range() — scan a range and import iDRACs
migrations/
0001_initial.py # DellServer / DellComponent schema
templates/netbox_idrac_inventory/ # detail pages + Device-page panel
tests/
test_models.py # Model unit tests
test_idrac.py # Sync engine + network/LLDP tests (fake client)
test_api.py # REST API tests (NetBox APIViewTestCases)
test_forms.py # Device-creating form + password handling
test_discovery.py # Target expansion + discovery engine
test_utils.py # Address helpers + encryption fail-closed
test_views.py # Bulk sync action
__init__.py # PluginConfig (settings) + post_migrate hook
choices.py # SyncStatusChoices, ComponentTypeChoices
models.py # DellServer, DellComponent, DellScanRange
forms.py # Forms (DellServerForm creates/links the Device)
tables.py # DellServerTable, DellComponentTable
filtersets.py # DellServerFilterSet, DellComponentFilterSet
views.py # CRUD views + DellServerSyncView
urls.py # UI URL routes
navigation.py # Plugin menu
template_content.py # Dell panel on the Device page
jobs.py # DellSyncJob + enqueue_sync()
signals.py # post_migrate: create LLDP custom fields
utils.py # default_device_name(), get_or_create_manufacturer()
Metadata
Release files for netbox-idrac-inventory 0.3.3
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_idrac_inventory-0.3.3.tar.gz | 71.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| netbox_idrac_inventory-0.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.5 kB
Release files / netbox_idrac_inventory-0.3.3.tar.gz
| Download URL | netbox_idrac_inventory-0.3.3.tar.gz |
|---|---|
| Size | 71.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7c019bdd6627aaf42ea699a6b4ae1a4721cc354043d3099667caccbcd7df1f11
|
|
BLAKE2b-256 checksum How to use checksums |
807a4fb02b70ec1098369fd24e80c3d797f395822a8f38e3d76ec39a9bbb7682
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / netbox_idrac_inventory-0.3.3-py3-none-any.whl
| Download URL | netbox_idrac_inventory-0.3.3-py3-none-any.whl |
|---|---|
| Size | 82.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f341d3e64fa83bafd5f593c532bb227408427c1612107725baf31f202f95b896
|
|
BLAKE2b-256 checksum How to use checksums |
45f15342074e3345375a39dbd17e7e9fc4094f3fab797580ca4c429e777416f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|