Skip to content

Introduce IP address pools with hierarchy and synchronous allocation#26

Merged
scotwells merged 5 commits into
mainfrom
ippool-ipclaim-ipallocation
May 23, 2026
Merged

Introduce IP address pools with hierarchy and synchronous allocation#26
scotwells merged 5 commits into
mainfrom
ippool-ipclaim-ipallocation

Conversation

@scotwells
Copy link
Copy Markdown
Contributor

@scotwells scotwells commented May 22, 2026

What this does

Introduces three new resource kinds that give operators and workloads a clean, purpose-built model for managing IP address space:

  • IPPool — an operator-defined block of address space (e.g. 10.0.0.0/8). Pools can be nested: a child pool carves a sub-block out of its parent automatically when created. Visibility controls whether a pool is available only within a project (platform/consumer) or shared across projects (shared).
  • IPClaim — a workload's request for an address block from a pool. Creating a claim synchronously returns the allocated CIDR in the response — no polling required. Deleting a claim immediately releases the address back to the pool.
  • IPAllocation — the system-managed record of what was allocated. Created and deleted automatically alongside the claim; protected from accidental direct deletion.

Why it matters

  • Simpler model — pools carry their CIDR and visibility directly; the separate IPPrefixClass indirection is gone
  • Hierarchical pools — teams can carve regional or environment sub-pools from a shared parent without operator involvement per allocation
  • Synchronous allocation — callers get their CIDR in the CREATE response body, eliminating the watch-and-poll pattern
  • Automatic cleanup — deleting a claim also removes its allocation record and returns capacity to the pool in the same transaction

Verified

  • 9/9 e2e suites pass on a live kind cluster (claim lifecycle, pool hierarchy, exhaustion, overlap prevention, pool selector, claim validation, multi-tenant isolation, host-address allocation)
  • k6 load tests: claim throughput p95 8ms (threshold < 500ms), exhaustion deny p95 18ms (< 200ms), read list p95 30ms (< 200ms), success rate 99.98%

Closes #25.

🤖 Generated with Claude Code

@scotwells scotwells force-pushed the ippool-ipclaim-ipallocation branch from 8c1ea81 to 4dee455 Compare May 22, 2026 18:03
@scotwells scotwells changed the base branch from worktree-agent-ad8b5ab26ad87a925 to main May 22, 2026 18:03
@scotwells scotwells changed the title feat: introduce IPPool, IPClaim, and IPAllocation (issue #25) Introduce IP address pools with hierarchy and synchronous allocation May 22, 2026
Single-address allocation is handled via IPClaim against a /32 or /128
pool. The dedicated IPAddress and IPAddressClaim resource kinds and all
associated registry, client, informer, and lister code are removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@scotwells scotwells force-pushed the ippool-ipclaim-ipallocation branch from 4dee455 to 8037dc2 Compare May 22, 2026 18:50
Adds three new resource kinds to the IPAM API:

IPPool (cluster-scoped) defines an allocatable block of address space.
Root pools carry a CIDR directly; child pools carve a sub-block out of a
parent pool synchronously at creation time. Visibility controls whether
a pool is available within a single project or shared across projects,
replacing the previous IPPrefixClass indirection.

IPClaim (namespace-scoped) is a workload's request for an address block.
Creating a claim returns the allocated CIDR synchronously in the response
body. Deleting a claim immediately releases the block back to the pool.

IPAllocation (namespace-scoped) is the system-managed record of what was
allocated, created and deleted atomically with the claim. It is protected
from accidental direct deletion.

All allocation transactions use SELECT FOR UPDATE on the parent pool row,
providing O(1) locking regardless of pool utilisation and eliminating
the conflict window that eventual-consistency approaches carry.

Verified: 9/9 e2e suites pass on a live kind cluster; k6 load tests show
claim throughput p95 at 8ms (threshold <500ms) and read list p95 at 30ms
(threshold <200ms).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@scotwells scotwells force-pushed the ippool-ipclaim-ipallocation branch from 5e51df2 to 2d86166 Compare May 22, 2026 18:53
scotwells and others added 2 commits May 22, 2026 16:25
… feedback

- IPPoolStatus.CIDR → AllocatedCIDR (json: allocatedCIDR) across both root
  and child pools; matches IPClaimStatus.AllocatedCIDR naming convention
- IPPool condition type "Ready" → "Allocated", reason "PoolReady" →
  "AllocationSucceeded"; child pool message includes parent pool name
- IPAllocation: remove spec.cidr (system-assigned, belongs in status);
  remove status.cidr and status.capacity (redundant/wrong scope);
  add status.allocatedCIDR as the canonical allocated block field
- Move ipFamily defaulting for child pools from allocator to registry
  storage layer (explicit before AllocatePrefix call)
- Remove redundant allocation.Strategy fallback from AllocatePrefix;
  PrepareForCreate guarantees the field is set before storage
- Delete stale prefix-* e2e suites (IPPrefixClaim/IPPrefix resource kinds
  no longer exist); update all e2e fixtures to status.allocatedCIDR
- Update cmd/ipam help text and internal/metrics comments to current names

All 9 e2e suites pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…QF1008

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@scotwells scotwells requested a review from privateip May 22, 2026 22:10
… add interface assertions

- Rename ipam_prefix_allocations → ipam_cidr_allocations to match the
  IPPool/IPClaim/IPAllocation API rename; update all SQL references
- Consolidate migrations 001 + 002 into a single 001_initial_schema.sql
  (service is pre-release; no live databases to migrate)
- Fix isChildPool always passed as false: add parameter to PrefixAllocator
  interface; ippool storage passes true, ipclaim storage passes false
- Add compile-time interface assertions to ipclaim/storage.go and
  ipallocation/storage.go (caught by code review)
- Add FROM --platform=$BUILDPLATFORM to Dockerfile builder stage so
  docker buildx cross-compiles arm64 natively instead of via QEMU

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@scotwells scotwells merged commit 3545525 into main May 23, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce IPPool, IPClaim, and IPAllocation to replace IPPrefix/IPPrefixClaim

2 participants