mcpField
N
netbox-diode

netbox-diode

github.com/netboxlabsData & databases2149 installsUpdated 2w ago
Repository

About netbox-diode

netbox-diode is a skill covering the open-source Python and Go SDKs for sending data to NetBox through Diode. It helps developers ingest related infrastructure objects without managing dependency order or IDs; Diode is write-only.

Key features

  1. 01Python and Go SDK guidance
  2. 02Name-based entity references
  3. 03Automatic dependency resolution
  4. 04Batch ingestion and chunking
  5. 05Dry-run and OTLP client options

Use cases

  1. 01Bulk import or migration into NetBox
  2. 02Submitting network discovery results
  3. 03Ingesting related devices, interfaces, and IPs

MCP support

The skill notes that a NetBox MCP server, if configured, can be used to verify objects after Diode ingestion.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/netboxlabs/skills --skill netbox-diode

After installing, type/netbox-diodein Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
entity-catalog.md
go-sdk-guide.md
ingestion-patterns.md
python-sdk-guide.md

Details

From the project README

NetBox Diode SDK

Diode is a gRPC-based data ingestion service for NetBox. Instead of managing dependency order and object IDs via the REST API, you describe objects by name and the Diode reconciler resolves dependencies, creates missing objects, and performs upserts automatically.

This skill covers the open-source Python and Go SDKs (diode-sdk-python v1.14.2 / diode-sdk-go v1.12.0), targeting NetBox 4.5–4.7. Both SDKs regenerated their entity set for NetBox 4.7.0 (python 1.14.0 / go 1.12.0). The Diode server and reconciler are proprietary — this skill describes their observable behavior, not internals.

Your knowledge of Diode SDK may be outdated. Entity types, SDK methods, and reconciler behavior evolve between releases. Prefer retrieval over pre-trained knowledge.

Retrieval Sources

SourceURL / MethodUse for
Diode docshttps://netboxlabs.com/docs/diode/Architecture, getting started
Diode Python SDKhttps://netboxlabs.com/docs/diode/sdk/python/Python SDK reference
Python SDK repohttps://github.com/netboxlabs/diode-sdk-pythonSource, entity types, changelog
Go SDK repohttps://github.com/netboxlabs/diode-sdk-goSource, entity types, changelog
Protobuf referencehttps://netboxlabs.com/docs/diode/diode-proto/Entity schema definitions
NetBox MCP serverIf configured — verify objects created by Diode landed correctlyPost-ingestion validation

For a quick comparison of Diode vs REST API, see netbox-api-integration/references/diode-integration.md.

FIRST: Verify Setup

Confirm the Diode SDK is installed and your credentials are configured:

# Python
pip show netboxlabs-diode-sdk

# Environment variables (recommended)
echo $DIODE_CLIENT_ID   # Should be set
echo $DIODE_CLIENT_SECRET  # Should be set

If the SDK is not installed: pip install netboxlabs-diode-sdk

To verify Diode server connectivity:

from netboxlabs.diode.sdk import DiodeClient
with DiodeClient(target="grpc://YOUR_DIODE_HOST:8080/diode", app_name="test", app_version="0.1") as client:
    print("Connected")  # Will raise DiodeConfigError if auth fails

When to Use Diode

ScenarioRecommended
Network discovery pushing many objectsDiode
Bulk import / migrationDiode
Creating many related objects (devices + interfaces + IPs)Diode
Reading / querying NetBox dataREST or GraphQL (Diode is write-only)
Single object CRUD with immediate read-backREST API
Complex filtered searchesREST or GraphQL

Key advantages over REST: No dependency ordering, no ID lookups, automatic object creation, gRPC performance for high volume.

Key limitation: Write-only. You cannot query NetBox through Diode.

Quick Reference

Client Types
ClientPythonGoPurpose
StandardDiodeClientdiode.NewClientProduction ingestion (requires Diode server)
Dry RunDiodeDryRunClientdiode.NewDryRunClientJSON output for testing (no server needed)
OTLPDiodeOTLPClientdiode.NewOTLPClientExport as OpenTelemetry log records
Authentication

OAuth2 client credentials via environment variables (recommended):

export DIODE_CLIENT_ID="your-client-id"
export DIODE_CLIENT_SECRET="your-client-secret"

Or pass directly: client_id= / client_secret= (Python), WithClientID() / WithClientSecret() (Go).

Minimal Python Example
from netboxlabs.diode.sdk import DiodeClient
from netboxlabs.diode.sdk.ingester import Device, Interface, IPAddress, Entity

with DiodeClient(
    target="grpc://localhost:8080/diode",
    app_name="my-discovery",
    app_version="1.0.0",
) as client:
    entities = [
        Entity(device=Device(
            name="sw-01",
            device_type="Catalyst 9300",
            manufacturer="Cisco",
            site="NYC-DC1",
            role="Access Switch",
            status="active",
        )),
        Entity(interface=Interface(device="sw-01", name="Gi0/1", type="1000base-t")),
        Entity(ip_address=IPAddress(address="10.0.1.1/24")),
    ]
    response = client.ingest(entities=entities)
    if response.errors:
        for err in response.errors:
            print(f"Error: {err}")
Minimal Go Example
import diode "github.com/netboxlabs/diode-sdk-go/diode"  // exported types live in the diode/ subpackage

client, err := diode.NewClient(
    "grpc://localhost:8080/diode",
    "my-discovery",
    "1.0.0",
    diode.WithClientID("YOUR_CLIENT_ID"),
    diode.WithClientSecret("YOUR_CLIENT_SECRET"),
)
if err != nil { log.Fatal(err) }
defer client.Close()

entities := []diode.Entity{
    &diode.Device{
        Name:       diode.String("sw-01"),
        DeviceType: &diode.DeviceType{Model: diode.String("Catalyst 9300")},
        Site:       &diode.Site{Name: diode.String("NYC-DC1")},
        Role:       &diode.DeviceRole{Name: diode.String("Access Switch")},
        Status:     diode.String("active"),
    },
}
resp, err := client.Ingest(context.Background(), entities)

Entity Construction

String Shorthand (Python only)

Python entities with a primary key in PRIMARY_VALUE_MAP accept string shorthand for nested references:

# These are equivalent:
Device(name="sw-01", site="NYC-DC1")
Device(name="sw-01", site=Site(name="NYC-DC1"))

Use full objects when you need to set attributes beyond the primary key:

Device(name="sw-01", site=Site(name="NYC-DC1", status="active", region="US-East"))

Go has no string shorthand. Always use full struct types with pointer helpers (diode.String(), diode.Int()).

Required Fields

Most entities only require their primary identifying field (e.g., name for Device, address for IPAddress). The reconciler creates referenced objects automatically. See references/entity-catalog.md for the full list.

Key Uniqueness Constraints
EntityUnique By
Devicename + site + tenant
Interfacename + device
IPAddressaddress + vrf
Prefixprefix + vrf
VLANvid + group

Reconciler Behavior

The reconciler is the server-side component that processes ingested data. Key observable behaviors:

  1. Automatic dependency resolution — referencing site="NYC-DC1" creates the Site if it doesn't exist
  2. Name-based matching — objects matched by their primary identifying field
  3. No ordering required — unlike REST, you don't need to create manufacturers before device types
  4. Upsert semantics — matching entities are updated, not duplicated
  5. Slug auto-generation — slug derived from name if not provided
  6. Case-sensitive matching — "Site ABC" ≠ "site abc"
  7. Producer provenance — entities tagged with app_name / app_version for audit

Ingestion Patterns

Batch Ingestion

Send multiple entities in one call:

response = client.ingest(entities=[
    Entity(device=device1),
    Entity(device=device2),
    Entity(interface=iface1),
], metadata={"batch_id": "scan-001"})
Chunked Ingestion (large batches)

gRPC has a ~4MB message limit. Use built-in chunking for large payloads:

from netboxlabs.diode.sdk import create_message_chunks

for chunk in create_message_chunks(entities):  # default 3MB chunks
    client.ingest(entities=chunk)

Go: client.Ingest(ctx, entities, diode.WithChunking(0)) (0 = default 3MB).

Dry Run and OTLP

See references/ingestion-patterns.md for dry run testing, replay, and OTLP export.

Error Handling

Python Exception Hierarchy
DiodeConfigError          # Bad credentials, unreachable auth endpoint
DiodeClientError          # gRPC transport errors (inherits grpc.RpcError; has .code(), .details())
OTLPClientError           # OTLP export failures

Note: DiodeClientError inherits from grpc.RpcError, so except grpc.RpcError also catches it.

Auto-Retry on Auth Expiry and Auth Backoff

Both SDKs retry on UNAUTHENTICATED gRPC errors (token expiry), up to 3 attempts by default (max_auth_retries / DIODE_MAX_AUTH_RETRIES). The same limit governs the OAuth2 token request itself:

  • Token fetch backoff (python 1.13+, go 1.10+): a 429, 500, 502 or 503 from /auth/token is retried with exponential backoff (1s doubling, capped at 30s, with jitter); Retry-After is honoured on 429/503. Any other non-200 status fails immediately with DiodeConfigError (Python) / an authentication failed error (Go).
  • Proactive refresh (go 1.11.1+): the Go client renews the access token about one minute before its expires_in lifetime ends, and coalesces concurrent refreshes onto a single token request. The Python client re-authenticates only after an UNAUTHENTICATED response.
  • Set DIODE_MAX_AUTH_RETRIES=1 for a single attempt with no retry (Go rejects values ≤ 0; Python does not validate the value).
Recommended Pattern
from netboxlabs.diode.sdk.exceptions import DiodeClientError, DiodeConfigError

try:
    with DiodeClient(target=target, app_name="app", app_version="1.0") as client:
        response = client.ingest(entities=entities)
        if response.errors:  # Per-entity validation errors
            for err in response.errors:
                log.warning(f"Entity error: {err}")
except DiodeConfigError as e:
    log.error(f"Config/auth error: {e}")
except DiodeClientError as e:
    log.error(f"gRPC error: {e.status_code} - {e.details}")

Anti-Patterns

  1. IPAddress requires CIDR — "192.168.1.1/24", not "192.168.1.1"
  2. Interface requires device — name alone isn't unique without device context
  3. Go has no string shorthand — every nested reference needs a full struct
  4. Diode is write-only — use REST/GraphQL to read data back
  5. Case-sensitive matching — inconsistent casing creates duplicate objects
  6. gRPC 4MB limit — use chunking for large batches
  7. String shorthand limitations — can't set nested object attributes (use full objects)
  8. Metadata must be JSON-compatible — strings, numbers, booleans, lists, dicts only
  9. Service ports on 4.7 — use port_mappings=["tcp/53", "udp/53"]; protocol + ports still work but are deprecated in NetBox 4.7 (removed from the API in 5.0) and describe only single-protocol services

Version Notes

NetBox 4.7 (2026-09-02) — SDK python 1.14.x / go 1.12.0
  • New entity types: CoolingSource, CoolingFeed, CoolingIntake, CoolingOutflow, ModuleBayType, plus a minimal User (only used as RackReservation.user). Ingest these only against NetBox 4.7 with a matching Diode plugin.
  • New fields: Device.cooling_method; DeviceType/ModuleType.cooling_method + end_of_life; ModuleType/ModuleBay.module_bay_types; Rack/RackType.cooling_capability + cooling_capacity; Interface.channels + channel_id (channelized subinterfaces) and writable Interface.mac_address; Service.port_mappings. Full list in references/entity-catalog.md.
  • Reading back what Diode wrote on 4.7: selection custom fields come back from REST/GraphQL as {"value": ..., "label": ...} objects; config_context is present by default (omit it with ?omit=config_context on 4.7.3+) on devices/VMs. See netbox-api-integration.
  • python 1.14.2 (2026-10-06): DIODE_SKIP_TLS_VERIFY=true now keeps the connection on TLS and skips only certificate verification; earlier releases opened a plaintext channel instead. Details in references/python-sdk-guide.md.
NetBox 4.6 — SDK python 1.12.0 / go 1.9.0
  • Added CableBundle, RackGroup, VirtualMachineType, ScriptModule, DeviceConfig.

References

FileWhen to Load
references/entity-catalog.mdNeed the full list of 110 entity types and their fields, including the NetBox 4.7 additions
references/python-sdk-guide.mdBuilding a Python integration — setup, patterns, examples
references/go-sdk-guide.mdBuilding a Go integration — setup, patterns, examples
references/ingestion-patterns.mdAdvanced patterns: chunking, dry run, OTLP, metadata
Cross-Skill References

Comments

Markdown supported