5.5 KiB
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-foundation | 03 | netbox |
|
|
|
|
|
|
Phase 1 Plan 03: NetBox Provisioning Summary
One-liner: Idempotent NetBox provisioner for 8 HWLab custom fields and Site→Location→Rack hierarchy using go-netbox v4 typed API.
What Was Built
internal/netbox/provision.go
Provisioning functions implementing check-before-create idempotency:
CustomFieldSpec— typed struct describing a NetBox custom field to provisionhwlabCustomFields— canonical slice of all 8 HWLab custom field specscustomFieldSpec(name)— lookup by name (used in tests)ProvisionCustomFields(ctx)— creates missing fields, skips existing; returns count createdcustomFieldExists(ctx, name)— checks viaExtrasCustomFieldsList().Name([]string{name})createCustomField(ctx, spec)— usesWritableCustomFieldRequestwithPatchedWritableCustomFieldRequestTypeenumProvisionLocationHierarchy(ctx)— creates Site "Homelab" → Location "Lab Bench" → Rack "Primary Rack"ensureSite/ensureLocation/ensureRack— check-then-create with proper go-netbox v4 typesCheckNetBoxInventoryPlugin(ctx)— GET /api/plugins/ to detect netbox-inventory pluginProvision(ctx)— top-level entry point calling both custom fields and location hierarchy
internal/netbox/provision_test.go
4 unit tests, all passing:
TestCustomFieldSpec— hw_id spec has type=text and ObjectTypes contains dcim.deviceTestCustomFieldSpecCatalogStatus— catalog_status is type=text (not selection)TestCustomFieldSpecPhotoURLs— photo_urls has a non-empty descriptionTestAllEightFieldsDefined— all 8 expected field names present, len=8
scripts/provision-netbox.go
Standalone CLI with //go:build ignore tag:
- Loads .env via
godotenv.Load() - Reads
HWLAB_NETBOX_URLandHWLAB_NETBOX_TOKEN - Calls
client.Provision(ctx)thenclient.CheckNetBoxInventoryPlugin(ctx) - Usage:
go run scripts/provision-netbox.go
Provisioning Status
Ran against live NetBox: No — HWLAB_NETBOX_TOKEN=homelab-netbox-api-token-2024 is a placeholder (22 chars, not a real NetBox token). Integration tests correctly skip.
To provision the live NetBox instance (LXC 130):
- Obtain a real API token from NetBox UI at http://10.5.0.130:8000/
- Set
HWLAB_NETBOX_TOKEN=<40-char-token>in.env - Run:
go run scripts/provision-netbox.go
go-netbox v4 API Notes
- Custom field type enum:
PatchedWritableCustomFieldRequestType(shared betweenWritableCustomFieldRequestandPatchedWritableCustomFieldRequest) — casting string directly works:nb.PatchedWritableCustomFieldRequestType("text") - Site/Location/Rack oneOf site field:
DeviceWithConfigContextRequestSiteis a oneOf union type; usenb.Int32AsDeviceWithConfigContextRequestSite(&siteID)to pass an integer ID - Location oneOf site field: Same pattern —
DeviceWithConfigContextRequestSiteused byWritableLocationRequest - Rack location field:
NullableDeviceWithConfigContextRequestLocation— usenb.Int32AsDeviceWithConfigContextRequestLocation(&locationID)thenreq.SetLocation(loc) - DcimRacksList Name filter:
DcimRacksList(ctx).Name([]string{name})works correctly (same pattern as custom fields) - GetId() returns
int32on Site, Location, and Rack models — consistent
Deviations from Plan
None — plan executed exactly as written. All stub pseudocode was replaced with real go-netbox v4 API calls. The CheckNetBoxInventoryPlugin function uses the HTTP client from c.api.GetConfig().HTTPClient to avoid importing net/http separately, with the base URL derived by stripping the /api suffix from c.url.
Known Stubs
None — all functions are fully implemented. Live provisioning requires a real NetBox token (currently placeholder in .env).
Self-Check
Files created:
- internal/netbox/provision.go: FOUND
- internal/netbox/provision_test.go: FOUND
- scripts/provision-netbox.go: FOUND
Commits:
07130d2— test(01-03): add failing tests for custom field spec and provisioning9b4cc9a— feat(01-03): implement custom field provisioning with go-netbox v449a729a— feat(01-03): add location hierarchy provisioning and provision CLI script
go build ./...: PASS
go vet ./...: PASS
go test ./internal/netbox/... -run "TestCustomFieldSpec|TestAllEight": PASS (4 tests)
Integration tests: SKIP (placeholder token — correct behavior)