docs(01-03): complete NetBox provisioning plan summary
This commit is contained in:
parent
d1192c3380
commit
52e3e9cd9c
1 changed files with 111 additions and 0 deletions
111
.planning/phases/01-foundation/01-03-SUMMARY.md
Normal file
111
.planning/phases/01-foundation/01-03-SUMMARY.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
phase: 01-foundation
|
||||
plan: "03"
|
||||
subsystem: netbox
|
||||
tags: [go, netbox, provisioning, custom-fields, dcim, tdd]
|
||||
dependency_graph:
|
||||
requires: [internal/netbox.Client]
|
||||
provides: [internal/netbox.Provision, internal/netbox.ProvisionCustomFields, internal/netbox.ProvisionLocationHierarchy]
|
||||
affects: [internal/quality, internal/hwid, scripts/provision-netbox.go]
|
||||
tech_stack:
|
||||
added: []
|
||||
patterns: [idempotent-provisioning, check-before-create, tdd-red-green]
|
||||
key_files:
|
||||
created:
|
||||
- internal/netbox/provision.go
|
||||
- internal/netbox/provision_test.go
|
||||
- scripts/provision-netbox.go
|
||||
modified: []
|
||||
decisions:
|
||||
- id: NB-PROV-01
|
||||
summary: "Use PatchedWritableCustomFieldRequestType(spec.Type) to convert string type to go-netbox enum — no separate mapping table needed"
|
||||
- id: NB-PROV-02
|
||||
summary: "Use Int32AsDeviceWithConfigContextRequestSite/Location helpers to pass IDs in oneOf union types for location/rack creation"
|
||||
- id: NB-PROV-03
|
||||
summary: "photo_urls stored as text (comma-separated) not multiselect — avoids NetBox multi-object custom field complexity"
|
||||
metrics:
|
||||
duration: "~20 minutes"
|
||||
completed: "2026-04-10T06:15:00Z"
|
||||
tasks_completed: 2
|
||||
files_created: 3
|
||||
files_modified: 0
|
||||
---
|
||||
|
||||
# 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 provision
|
||||
- `hwlabCustomFields` — canonical slice of all 8 HWLab custom field specs
|
||||
- `customFieldSpec(name)` — lookup by name (used in tests)
|
||||
- `ProvisionCustomFields(ctx)` — creates missing fields, skips existing; returns count created
|
||||
- `customFieldExists(ctx, name)` — checks via `ExtrasCustomFieldsList().Name([]string{name})`
|
||||
- `createCustomField(ctx, spec)` — uses `WritableCustomFieldRequest` with `PatchedWritableCustomFieldRequestType` enum
|
||||
- `ProvisionLocationHierarchy(ctx)` — creates Site "Homelab" → Location "Lab Bench" → Rack "Primary Rack"
|
||||
- `ensureSite` / `ensureLocation` / `ensureRack` — check-then-create with proper go-netbox v4 types
|
||||
- `CheckNetBoxInventoryPlugin(ctx)` — GET /api/plugins/ to detect netbox-inventory plugin
|
||||
- `Provision(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.device
|
||||
- `TestCustomFieldSpecCatalogStatus` — catalog_status is type=text (not selection)
|
||||
- `TestCustomFieldSpecPhotoURLs` — photo_urls has a non-empty description
|
||||
- `TestAllEightFieldsDefined` — 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_URL` and `HWLAB_NETBOX_TOKEN`
|
||||
- Calls `client.Provision(ctx)` then `client.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):
|
||||
1. Obtain a real API token from NetBox UI at http://10.5.0.130:8000/
|
||||
2. Set `HWLAB_NETBOX_TOKEN=<40-char-token>` in `.env`
|
||||
3. Run: `go run scripts/provision-netbox.go`
|
||||
|
||||
## go-netbox v4 API Notes
|
||||
|
||||
- **Custom field type enum:** `PatchedWritableCustomFieldRequestType` (shared between `WritableCustomFieldRequest` and `PatchedWritableCustomFieldRequest`) — casting string directly works: `nb.PatchedWritableCustomFieldRequestType("text")`
|
||||
- **Site/Location/Rack oneOf site field:** `DeviceWithConfigContextRequestSite` is a oneOf union type; use `nb.Int32AsDeviceWithConfigContextRequestSite(&siteID)` to pass an integer ID
|
||||
- **Location oneOf site field:** Same pattern — `DeviceWithConfigContextRequestSite` used by `WritableLocationRequest`
|
||||
- **Rack location field:** `NullableDeviceWithConfigContextRequestLocation` — use `nb.Int32AsDeviceWithConfigContextRequestLocation(&locationID)` then `req.SetLocation(loc)`
|
||||
- **DcimRacksList Name filter:** `DcimRacksList(ctx).Name([]string{name})` works correctly (same pattern as custom fields)
|
||||
- **GetId()** returns `int32` on 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 provisioning
|
||||
- 9b4cc9a — feat(01-03): implement custom field provisioning with go-netbox v4
|
||||
- 49a729a — 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)
|
||||
|
||||
## Self-Check: PASSED
|
||||
Loading…
Add table
Reference in a new issue