Skip to content

feat(lb): Octavia load-balancer family (pcd_lb_*) — Phase 3 - #16

Merged
PF9-pushkar merged 2 commits into
mainfrom
feat/lb-octavia
Jul 12, 2026
Merged

feat(lb): Octavia load-balancer family (pcd_lb_*) — Phase 3#16
PF9-pushkar merged 2 commits into
mainfrom
feat/lb-octavia

Conversation

@PF9-pushkar

Copy link
Copy Markdown
Collaborator

First Phase 3 family — Octavia load balancing. New internal/services/loadbalancer package + a LoadBalancerV2Client (catalog type load-balancer) on the shared config.

Resources & data source

Type
pcd_lb_loadbalancer root — VIP by subnet/network, cascade delete + wait-for-DELETED
pcd_lb_listener protocols, TLS refs, timeouts (ms), insert-headers, allowed-CIDRs
pcd_lb_pool LB method, session persistence (nested object)
pcd_lb_member backend address/port/weight, composite import
pcd_lb_monitor health checks (HTTP probe fields gated on type)
pcd_lb_l7policy / pcd_lb_l7rule L7 routing; rule uses composite import
pcd_lb_loadbalancer (data source) lookup by id/name

The defining complexity: Octavia serializes per load balancer

After any change to the LB or a child, the root LB enters PENDING_* and the API rejects further changes with 409 until it returns to ACTIVE. So every child resolves its root LB (listener→LB, pool→LB or via listener, member/monitor→pool→LB, l7policy→listener→LB, l7rule→policy→listener→LB) and waits for provisioning_status = ACTIVE before and after each mutation. The root LB delete cascades and waits for 404.

Churny/server-filled collection fields (listener sni_container_refs/allowed_cidrs/insert_headers) are echo-only to avoid perpetual diffs.

Adversarial review fix included

The review caught a real bug: pcd_lb_pool's loadbalancer_id/listener_id are mutually-exclusive Optional+Computed — the unset one is planned unknown on create, and the old code only filled them when both were empty, so an unknown reached state → "inconsistent result after apply" on every pool create. Fixed to fill each independently (gated on IsNull/IsUnknown so a plain read can't re-derive a sibling and force a spurious replace).

Checks

go build/vet/gofmt/golangci-lint (0 issues), tfplugindocs generate (pages under the "Load Balancer" subcategory), and terraform fmt on the new examples all clean. A full-tree acceptance test is included.

Live-validation status

Code-complete; static checks green + adversarially reviewed. Not run against the CE lab — Octavia is live (Step 0) but LB provisioning needs a working amphora/provider driver, and lab credentials weren't available this session. Tracked in DECISIONS.md.

Phase 3, flagship family. New internal/services/loadbalancer package plus a
LoadBalancerV2Client (catalog type "load-balancer") on the shared config.

Resources: pcd_lb_loadbalancer (root, cascade delete + wait-for-DELETED),
pcd_lb_listener, pcd_lb_pool (session persistence, clear via empty struct),
pcd_lb_member, pcd_lb_monitor (HTTP probe fields only for HTTP/HTTPS),
pcd_lb_l7policy, and pcd_lb_l7rule (composite import). Data source:
pcd_lb_loadbalancer.

Octavia serializes changes per load balancer: every child resource resolves its
ROOT load balancer (listener -> its LB; pool -> LB or via listener; member/monitor
-> pool -> LB; l7policy -> listener -> LB; l7rule -> policy -> listener -> LB) and
waits for provisioning_status to return to ACTIVE before and after each mutation,
so concurrent child edits don't hit 409 "immutable". Churny/server-filled
collection fields (listener SNI/allowed_cidrs/insert_headers) are echo-only.

Full-tree acceptance test, per-resource examples (with the "Load Balancer"
registry subcategory), CHANGELOG, and DECISIONS matrix included.
build/vet/gofmt/golangci-lint (0 issues) and tfplugindocs all clean.
…aches state

pcd_lb_pool's loadbalancer_id and listener_id are both Optional+Computed. The
user sets one; the other is planned unknown on create. readInto only filled them
when BOTH were empty, so the sibling stayed unknown and every pool apply failed
with 'inconsistent result after apply'. Fill each independently from the pool
result (defaulting to an empty string), gated on IsNull/IsUnknown so a plain read
never re-derives a sibling that would force replacement. Found by adversarial review.
@PF9-pushkar
PF9-pushkar merged commit eaff1b5 into main Jul 12, 2026
4 checks passed
@PF9-pushkar
PF9-pushkar deleted the feat/lb-octavia branch July 12, 2026 16:02
PF9-pushkar added a commit that referenced this pull request Jul 14, 2026
feat(lb): Octavia load-balancer family (pcd_lb_*) — Phase 3
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.

1 participant