- SUMMARY.md for plan 01-02 with go-netbox v4 API notes and deviation log
5.6 KiB
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-foundation | 02 | netbox |
|
|
|
|
|
|
Phase 1 Plan 02: NetBox Client Package Summary
One-liner: go-netbox v4 typed client wrapper with safe custom field read/write helpers and integration-skip guards for placeholder tokens.
What Was Built
internal/netbox/types.go
Domain types that decouple the rest of HWLab from go-netbox generated types:
Device— HWLab inventory item (ID, Name, AssetTag, CustomFields, Created, LastUpdated)CustomFields— typed struct over NetBox'smap[string]interface{}response (HWID, CatalogStatus, ProductURL, FirmwareVersion, TestDate, TestData, AINotes, PhotoURLs)
internal/netbox/client.go
Client struct wrapping *nb.APIClient with methods:
NewClient(url, token string) (*Client, error)— validates inputs, strips trailing/apifrom URL before passing tonb.NewAPIClientForPing(ctx)— lightweight connectivity check viaDcimDevicesList(limit=1)ListDevices(ctx, limit)— returns[]Devicemapped viadeviceFromNetBoxGetDevice(ctx, id)— retrieves single device by NetBox internal ID
internal/netbox/custom_fields.go
ParseCustomFields(raw map[string]interface{}) CustomFields— safe type assertions for all 8 HWLab custom field keys; handles nil input; handles[]interface{}photo_urlsBuildCustomFieldsPatch(hwID, catalogStatus string, photoURLs []string) map[string]interface{}— selective patch (only non-empty fields included)BuildFullCustomFieldsPatch(cf CustomFields) map[string]interface{}— full patch for initial record creation(c *Client) PatchCustomFields(ctx, deviceID, patch)— usesnb.PatchedWritableDeviceWithConfigContextRequest.SetCustomFields()then.Execute()
Integration Test Status
Integration tests (TestPingLive, TestListDevicesLive, TestPatchCustomFieldsRoundTrip) SKIPPED because HWLAB_NETBOX_TOKEN=homelab-netbox-api-token-2024 is a placeholder (22 chars, not 40).
Skip guard: if len(token) != 40 { t.Skip(...) } — correct behavior, no errors.
To run integration tests: set HWLAB_NETBOX_TOKEN to a real 40-char hex token from NetBox UI, and HWLAB_TEST_DEVICE_ID to an existing device ID for round-trip test.
go-netbox v4 API Notes
- Struct confirmed:
nb.PatchedWritableDeviceWithConfigContextRequestwithSetCustomFields(map[string]interface{})method - PATCH pattern:
c.api.DcimAPI.DcimDevicesPartialUpdate(ctx, int32(id)).PatchedWritableDeviceWithConfigContextRequest(req).Execute() - URL handling:
NewAPIClientForappends/apiinternally — must strip trailing/apifrom the URL in the config to avoidhttp://host:8000/api/api/ - AssetTag type:
NullableStringonDeviceWithConfigContext—GetAssetTag()returns empty string when null (safe) - CustomFields on read:
map[string]interface{}— requires type assertions per field
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] custom_fields.go written in Task 1 to unblock compilation
- Found during: Task 1 GREEN phase
- Issue:
client.gocallsParseCustomFieldswhich was planned for Task 2; package would not compile without it - Fix: Wrote
custom_fields.goas part of Task 1 implementation to makego testwork; Task 2 then added onlycustom_fields_test.go - Files modified: internal/netbox/custom_fields.go (created during Task 1 pass)
- Commit:
9f3ed9f(Task 1 commit includes custom_fields.go)
2. [Rule 2 - Missing] Added HWLAB_TEST_DEVICE_ID guard to round-trip integration test
- Found during: Task 2 test design
- Issue: Round-trip test needs an existing device ID — hardcoding one would fail on fresh NetBox installs
- Fix: Added second
t.Skip()guard whenHWLAB_TEST_DEVICE_IDenv var is absent - Files modified: internal/netbox/custom_fields_test.go
Self-Check
Files created:
- internal/netbox/client.go: FOUND
- internal/netbox/types.go: FOUND
- internal/netbox/client_test.go: FOUND
- internal/netbox/custom_fields.go: FOUND
- internal/netbox/custom_fields_test.go: FOUND
Commits:
go build ./...: PASS
go test ./internal/netbox/... -run TestNewClientValidation: PASS
go test ./internal/netbox/... -run "TestParseCustomFields|TestBuildCustomFields": PASS (5 tests)
Integration tests: SKIP (placeholder token — correct behavior)