Skip to content

feat(gateway-api): GEP-713 — Phase 1 (ALB) + Phase 2 (NLB/L4)#9

Open
anngdinh wants to merge 92 commits into
mainfrom
feature/gateway-api-gep713-phase1
Open

feat(gateway-api): GEP-713 — Phase 1 (ALB) + Phase 2 (NLB/L4)#9
anngdinh wants to merge 92 commits into
mainfrom
feature/gateway-api-gep713-phase1

Conversation

@anngdinh

@anngdinh anngdinh commented May 8, 2026

Copy link
Copy Markdown
Contributor

Update (2026-06-12) — Phase 2: NLB (L4) Gateway + InterVPC

Extends the Gateway path to VNGCloud Network Load Balancers (L4) and closes Service-controller L4 parity gaps. Same model as ALB: the gateway path emits the same LoadBalancerConfig (LBC) the Service type=LoadBalancer path emits, so the existing LBC controller drives the cloud. Each addition was verified field-by-field against the generated LBC and is unit- + envtest-covered.

  • ec0d95d — Phase 2 NLB (TCP/UDP): new vngcloud-nlb GatewayClass (gateway.vks.vngcloud.vn/nlb); TCPRoute/UDPRoute produce a Layer 4 LBC. Honors VKSGatewayPolicy (LB spec, listener timeouts, allowed CIDRs), VKSBackendPolicy (pool algorithm, stickiness, target type, node labels), VKSHealthCheckPolicy (TCP / PING-UDP / HTTP probe). TCP→TCP and UDP→PING-UDP health-check defaults mirror the Service controller. VKSRoutePolicy is L7-only and ignored. Disabled by default (--disable-nlb-gateway-controller) because TCPRoute/UDPRoute are experimental-channel CRDs the operator must install first; enable with gatewayApi.nlb.enabled=true.
  • ddecb22VKSBackendPolicy.proxyProtocol: switches a TCP pool to the vngcloud PROXY pool protocol so an L4 backend (e.g. an HAProxy ingress controller) recovers the real client IP behind the NLB. Mirrors the Service enable-proxy-protocol annotation. The cloud pool protocol is create-only.
  • c778188 — InterVPC scheme: add VKSLoadBalancerSpec.privateZoneId (→ LBC.Spec.PrivateZoneId, a common.Zone) — the missing piece for the InterVPC scheme (scheme + privateSubnetId were already wired). Wired on both the NLB and ALB paths. Mirrors the Service private-zone-id annotation; scheme: InterVPC matches v2.InterVpcLoadBalancerScheme.
  • Tests: ported Service/Ingress envtest scenarios onto the NLB path (ca7c808, 9c79e50); unit + envtest for proxyProtocol and InterVPC.
  • Docs: an NLB/L4 user guide, a "Real client IP (NLB + HAProxy + PROXY protocol)" guide (labbed end-to-end on a live cluster — app sees the real public client IP), and an InterVPC section.

Remaining Service-controller L4 gap: automatic NodeSecurityGroup management (the gateway path creates no NSG) — deferred, same posture as the ALB path.


Update (2026-06-10) — ALB LB-level & health-check parity

Two follow-up commits bring the ALB Gateway path to parity with the Ingress annotations for several LoadBalancerConfig (LBC) fields. Both paths emit the same LBC, so each was verified field-by-field against the generated LBC and is unit-tested (TDD) in alb_gateway_uc.

  • 0c88ad6VKSHealthCheckPolicy: added port (→ every pool member's MonitorPort), httpHealthCheck.method (GET/PUT/POST), httpHealthCheck.httpVersion (1.0/1.1). HTTP-only fields are ignored for TCP probes; mirrors the Ingress healthcheck-port / healthcheck-http-method / healthcheck-http-version annotations.
  • f1f955aVKSGatewayPolicy.loadBalancerSpec: added loadBalancerName and preferZoneId, and wired full BYO-LB adoption via loadBalancerIdresolveSubnetAndZone now mirrors the adopted LB's subnet/zone so the LBC matches the LB the LBC controller adopts. Precedence matches Ingress: loadBalancerId (adopt) > subnetId > preferZoneId > cluster defaults. Subnet/zone resolution now runs create-time only (keeps VNGCloud lookups off the per-reconcile hot path).

CRD bases + embedded copies regenerated; design-doc decision #6 updated to note BYO-LB adoption is now supported (the controller still never auto-adopts).

Remaining non-parity items are out of scope here: security-groups/NSG (intentionally deferred) and routing by header/method/query + fixed-response (genuine VNGCloud LB API limits that affect the Ingress path equally).

Note: the "No runtime behaviour yet / no controllers are wired up" framing in the original Summary below predates the Section F–H ALB use-case work (LB / listener / pool / policy / cert building) that has since landed on this branch.


Summary

Lands the foundation for Gateway API GEP-713 Phase 1 — Sections A–E of docs/superpowers/plans/2026-05-08-gateway-api-gep713-phase1.md. No runtime behaviour yet; CRDs install but no controllers are wired up.

What's included:

  • A — Bootstrap: sigs.k8s.io/gateway-api v1.2.0 dep; api/gateway/v1alpha1/ API group; finalizer + GatewayClass controller-name constants.
  • B — Policy CRDs: four CRDs (VKSGatewayPolicy, VKSBackendPolicy, VKSHealthCheckPolicy, VKSRoutePolicy) with deepcopy generated and embedded into the binary via register.go.
  • C — pkg/gateway/ helpers: hostname matching, deterministic synthetic-pool naming + weight scaling, policy target-ref matching. Unit tested.
  • D — internal/controller/gateway/shared/: protocol classifier, condition + ancestor-status helpers, match-specificity ordering, reverse indexer, finalizer helpers, cross-resource event handlers.
  • E — internal/usecase/gateway_uc/shared/: ReferenceGrant evaluator, generic Direct-policy resolver (oldest-wins), Matches() adapters on all four policy CRDs.

Plan deviations on the record

  1. make sync-embedded-crds only matched vks.vngcloud.vn_*.yaml — extended to gateway.vks.vngcloud.vn_*.yaml.
  2. register.go had no path for embedding the new gateway CRDs — added 4 //go:embed entries and GetAllCRDs() rows.
  3. shared_types.go aliases needed +kubebuilder:object:generate=false markers, otherwise controller-gen emits DeepCopy on external types.
  4. Status helper had a name collision (derefStr used for both *Group and *Kind) — split into derefGroup / derefKind.
  5. Build dep: go get sigs.k8s.io/gateway-api/apis/v1alpha2@v1.2.0 was needed in addition to the root module.

Why F–J are deferred

Section F (and downstream G/H/I) calls a high-level vngcloud_repo abstraction (SyncListeners, SyncPools, SyncPolicies, LoadBalancerParams, ImportCertificateFromSecret, EnsureNSGForGateway, …) that doesn't exist — the real VngCloudRepository is a thin shell over loadbalancerv2.ICreate*Request SDK types. The plan's own self-review (line 4747) flags these as "expected to exist." Section J user-docs would describe non-functional features without F–H, so they're held back too.

Plan revision needed before F can land.

Test plan

  • go build ./... clean
  • go test ./pkg/gateway/... ./internal/controller/gateway/shared/... ./internal/usecase/gateway_uc/shared/... — all pass
  • make test (full envtest suite) — reviewer to run; foundation only, no controllers wired up so no envtest specs added in this PR
  • make manifests clean re-run produces no diff (CRDs already in tree)

🤖 Generated with Claude Code

anngdinh and others added 27 commits May 8, 2026 08:44
Alternative to the AWS-LBC-style design (2026-04-30). All vngcloud
customization expressed as Direct Policy Attachment CRDs targeting
Gateway / Service / HTTPRoute via spec.targetRefs. No parametersRef,
no extensionRef, no LoadBalancerConfig extension.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This branch is a clean GEP-713 implementation; the AWS-style design
artifacts are not used here. They remain on feature/gateway-api-phase1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task-by-task plan for the L7 ALB MVP implementing the GEP-713 Direct
Policy Attachment design. Four VKS*Policy CRDs, ALB GatewayClass,
HTTPRoute support, and four policy validator reconcilers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tures

The v1alpha1 VKSPolicy schemas advertised fields the underlying vngcloud LB
v2 API doesn't expose. Verified against the vngcloud-go-sdk request schemas
(latest available); these are platform limits, not Phase-1 punts.

Removed fields:
  VKSGatewayPolicy: SSLPolicy, ALPNPolicy
  VKSBackendPolicy: TargetType, EnableProxyProtocol; replaced
    SessionAffinity{Type,CookieName,TTL} with Stickiness *bool (API exposes
    only an on/off flag, no cookie name or TTL)
  VKSHealthCheckPolicy: Port (uses member's monitorPort), HTTPHealthCheck.RequestHeaders
  VKSRoutePolicy: AdditionalMatches[Header/QueryParam/Method/SourceIP]
    (vngcloud rule types are HOST_NAME and PATH only); FixedResponse action
    (vngcloud actions are REJECT, REDIRECT_TO_URL, REDIRECT_TO_POOL only)

Added §1.6 to the design spec documenting the supported feature surface and
the HTTPRoute UnsupportedMatch handling for header/queryParam/method matches.

Regenerated deepcopy and CRD manifests; builds and unit tests pass.
@anngdinh anngdinh changed the base branch from v3 to main May 8, 2026 16:21
anngdinh added 2 commits May 8, 2026 16:32
…keleton)

Approach 1A: the Gateway controller is the only writer to a per-Gateway
LoadBalancerConfig CR; the existing LBC controller continues to drive the
cloud LB exactly as it does for Ingress/Service. Owner labels match the
existing convention (vks.vngcloud.vn/owner-resource-{kind,name,uid}) so
the LBC's ownership is greppable.

Phase A — usecase scaffolding:
  internal/usecase/contracts.go      — ALBGatewayUseCase interface
  internal/usecase/gateway_uc/alb_gateway_uc/usecase.go    — Init/Ensure/Delete entry points
  .../alb_gateway_uc/finalizer.go    — finalizer add/remove + delete-owned-LBC
  .../alb_gateway_uc/build_lbc.go    — defaultGatewayBuildTask, VKSGatewayPolicy
                                       resolver, LBC create/patch with the same
                                       Spec/Status discipline ingress_uc uses

Phase A only translates LB-level fields (Type, SubnetId, ZoneId,
LoadBalancerName, VpcId, ClusterId, Scheme, PackageId, Tags,
LoadBalancerId). Listeners/Pools/Policies/Certificates land in subsequent
phases and will extend buildLoadBalancerConfig in place.

Phase B — controller wiring:
  internal/controller/gateway/alb/gateway_controller.go    — reconciler with
    GatewayClass-name predicate, watches Gateway/HTTPRoute/VKSGatewayPolicy/
    LoadBalancerConfig/Service. Async init mirrors networking/ingress.
  internal/controller/gateway/alb/lbc_to_gateway.go        — handler that
    enqueues the owning Gateway when its LBC changes (status-mirror hook).
  cmd/main.go                                              — register schemes
    (gateway.networking.k8s.io v1 + v1beta1, gateway.vks.vngcloud.vn
    v1alpha1), add --disable-alb-gateway-controller flag (defaults to TRUE
    while Phase 1 is incomplete), construct + setup the reconciler.
  config/rbac/role.yaml                                    — regenerated from
    kubebuilder markers on the new reconciler.

Build clean; existing tests pass.
…e C)

For each Gateway.Spec.Listeners[i], emit a v1alpha1.Listener with:
  - protocol mapped from gwv1.ProtocolType (HTTP/HTTPS only — TCP/UDP/TLS
    rejected for ALB Phase 1)
  - port from Gateway listener
  - timeouts (Client/Member/Connection) from VKSGatewayPolicy, per-listener
    sectionName-scoped policy winning over unscoped policy field-by-field
  - allowedCidrs from VKSGatewayPolicy.AllowedCIDRs (joined with ',')
  - insertHeaders from VKSGatewayPolicy.InsertHeaders (map → []InsertHeader,
    sorted by key for stable Spec equality)
  - clientCertificateId from VKSGatewayPolicy.ClientCertificateID

Pool/cert/policy fields stay nil — Phase D adds TLS, Phase E adds Pools+Policies.

helpers.go centralizes the priority-ordered "first non-nil" pickers so each
field's resolution is one line in build_listeners.go.

Build clean.
anngdinh and others added 12 commits June 11, 2026 02:38
…ismatch

Opt-in (RUN_GATEWAY_E2E) live specs covering the three new behaviors:
- cross-ns backendRef reports RefNotPermitted, then ResolvedRefs once a
  ReferenceGrant is created;
- a route in a team=blue namespace attaches via a NamespacesFromSelector
  listener;
- a rule whose backends carry divergent policies reports BackendConfigMismatch.

These assert on HTTPRoute status (written on reconcile, no LB provisioning
wait). Require the controller to be running the current build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ackendConfigMismatch

The full-suite rerun caught the kitchen weighted rule being dropped by the
new BackendConfigMismatch fail-closed check (echo had backend/health-check
policies, echo-v2 had none). Both weighted backends now share the same
policies via multi-targetRefs.

New specs (all passing live, 17/17 focused run):
- ReferenceGrant revocation -> back to RefNotPermitted
- policy Accepted=False/TargetNotFound for a missing target
- HTTPRoute PartiallyInvalid/UnsupportedValue for the dropped header rule
- VKSRoutePolicy deletion reverts the rule action to REDIRECT_TO_POOL
- HTTPRoute deletion drops all listener policies
- preferZoneId positive: LBC created in the requested (valid) zone

Also: fix stale --enable-gateway-api-alb references (real flag is
--disable-alb-gateway-controller) and rename fail*YAML helpers to
gwPolicyYAML/plainGatewayYAML now that positive specs reuse them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New docs/guide/gateway-api.md covering: enabling via Helm
(gatewayApi.alb.enabled) / --disable-alb-gateway-controller, quick start,
HTTPRoute support matrix, the four GEP-713 policy CRDs with full field
examples, create-only fields and subnet/zone precedence, BYO-LB adoption,
conflict resolution + policy status, route status reasons (incl.
RefNotPermitted/BackendConfigMismatch/PartiallyInvalid), ReferenceGrant,
TLS termination, and an Ingress-annotation equivalence table.

Wire it into mkdocs nav, index/README feature lists, the configuration
flag/values tables, and contributing (opt-in gateway e2e). README roadmap:
Gateway API Phase 1 shipped. mkdocs build --strict passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the vngcloud-nlb GatewayClass and an L4 reconciler that translates a
Gateway + attached TCPRoute/UDPRoute into a Type=Network LoadBalancerConfig,
reconciled by the existing LBC controller (same cloud path as Service
type=LoadBalancer). Scope: TCP + UDP, modelled on the Service controller's L4
build. TLSRoute (SNI) deferred to a follow-up.

Translation (internal/usecase/gateway_uc/nlb_gateway_uc):
- Type=Network LBC; one TCP/UDP listener per supported Gateway listener, each
  with a single default pool from the oldest attached route's backendRefs.
- Members via instance/ip target type; weighted backends scaled; health monitor
  TCP (default) / PING-UDP (UDP) with VKSHealthCheckPolicy override.
- Honors VKSGatewayPolicy (LB spec + listener timeouts/CIDRs) and VKSBackendPolicy
  (algorithm/stickiness/target type). VKSRoutePolicy/certs/headers are L7-only.
- Cross-ns backendRefs gated by ReferenceGrant; Gateway + TCP/UDP route status.
- HTTP/HTTPS listeners on an nlb Gateway → UnsupportedProtocol (mixed rejected).

Controller (internal/controller/gateway/nlb) + wiring:
- Thin reconciler mirroring alb; watches TCP/UDP routes, VKS policies, LBC, Svc,
  ReferenceGrant. New L4 field indexes + eventhandlers in gateway/shared.
- cmd/main.go: --disable-nlb-gateway-controller (default TRUE / disabled) and
  gwv1alpha2 scheme registration. Disabled by default because TCPRoute/UDPRoute
  are Gateway-API experimental-channel CRDs and a deployment prerequisite.

Tests: unit (fake client) for protocol mapping, mixed rejection, pool from
route, LBC shape, route attachment/oldest-wins; envtest (experimental CRDs)
for GatewayClass Accepted + TCP Gateway→Type=Network LBC + route status.
Opt-in live e2e (RUN_GATEWAY_NLB_E2E) for TCP + UDP. ALB envtest still green.

Helm: gatewayApi.nlb.enabled (default false) + gatewayclass-nlb.yaml + flag.
config/rbac/role.yaml: tcproutes/udproutes (+status). Docs: docs/guide/gateway-nlb.md.

Note: the Helm manager-rbac.yaml is regenerated separately ([build] update: helm)
and already lacks all gateway RBAC since Phase 1 — config/rbac/role.yaml is the
kubebuilder source of truth and carries the new L4 rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live run proved the feature works — the controller created a Type=Layer4
LBC with the TCP/UDP listener+pool — but the spec asserted the wrong string
("Network"). Compare against the SDK constants (LoadBalancerTypeLayer4,
ListenerProtocol{TCP,UDP}, PoolProtocol{TCP,UDP}) instead of hardcoded strings.
Also swap the UDP backend to nginx (coredns crash-loops without a Corefile, which
hung rollout); the spec only asserts LBC shape, not UDP traffic.

Live NLB e2e (RUN_GATEWAY_NLB_E2E): 2/2 pass — TCP (Programmed + address +
TCPRoute Accepted) and UDP (Type=Layer4, UDP listener+pool). Clean teardown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unit (coverage_test.go): weighted backendRefs (scaled member weights),
zero-weight drop, ip target type (ResolvePodEndpoints), VKSBackendPolicy
overlay (algorithm/stickiness), VKSHealthCheckPolicy overlay (port override +
thresholds, HTTP probe over a TCP pool), listener policy (timeouts/CIDRs),
applyLoadBalancerSpec (scheme/tags/isPOC + nil-clears), resolveSubnetAndZone
(default / explicit subnetID / preferZone==default), resolveLoadBalancerName,
listAttachedRoutes (TCP+UDP), routeResolvedRefs (Resolved/BackendNotFound/
RefNotPermitted), routeAttaches multi-listener, listenerStatuses mixed
protocols (UnsupportedProtocol), buildListenersAndPools UDP happy path and
listener-without-route skipped.

Envtest (gateway_controller_test.go): UDP Gateway -> Type=Layer4 LBC with UDP
listener+pool; Gateway deletion removes the owned LBC via finalizer cleanup.

All green: nlb unit + envtest (4 specs, 29s), go build/vet clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…path

Brings the applicable, non-duplicate behavioral scenarios from the Service and
Ingress controller suites onto the NLB Gateway envtest (mock cloud, same level
as the source suites):

- listener port change reflected on the LBC (Service "update port")
- LB-level attributes from VKSGatewayPolicy -> LBC (Service "all annotations")
- subnetId from VKSGatewayPolicy.loadBalancerSpec -> LBC.SubnetId (Ingress
  "prefer subnet ID"; create-only, policy applied before the Gateway)

Dropped as not applicable to the Gateway architecture: NodeSecurityGroup /
CNI-tag scenarios (the Gateway path doesn't manage NSGs), "N services share one
LB" (1 Gateway = 1 LB), PROXY protocol (not in Phase 2), and TCP+UDP-same-port
(a cloud-enforced limit the mock can't exercise). ALB-equivalent LB-attr/
subnet/zone/HTTPS scenarios are already covered by the kitchen live e2e + unit.

nlb envtest: 7 specs green (43.9s).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Makefile `run`: add --disable-nlb-gateway-controller=false so local runs
  exercise the Phase 2 NLB controller alongside ALB.
- endpoint_resolver_test.go: switch the one gomega assertion to testify
  assert.NoError (the file otherwise uses testify); gomega's Expect without a
  registered fail handler panicked when run via `go test`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds proxyProtocol to VKSBackendPolicy. On the NLB (L4) path, a TCP pool
switches to the vngcloud PROXY pool protocol so an L4 backend (HAProxy/nginx
ingress controller) can recover the real client IP behind the NLB. TCP-only;
ignored for UDP. Mirrors the Service controller's enable-proxy-protocol
annotation. Pool protocol is fixed at create time, so set this before the
Gateway is created.

CRD + deepcopy regenerated (bases + embedded). Tests: unit (TCP->PROXY,
UDP untouched) + envtest (VKSBackendPolicy.proxyProtocol -> LBC pool PROXY).
nlb envtest green (8 specs, 60.9s).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document VKSBackendPolicy.proxyProtocol in the NLB guide and add an end-to-end
example (docs/examples/gateway-nlb-haproxy-realip.md): front an HAProxy ingress
controller with a vngcloud-nlb Gateway, enable PROXY protocol on the backend,
and have the app recover the real client IP via X-Forwarded-For. Manifests are
the ones verified live (whoami showed X-Forwarded-For = the real public egress IP).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the PROXY-protocol real-client-IP walkthrough from Examples into
the Guide section and fix the cross-links between it and the NLB guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Service controller supports the InterVPC LB scheme (private-subnet-id +
private-zone-id). The gateway path already carried scheme + privateSubnetId
but had no field for the client-subnet zone, so InterVPC could not be fully
expressed.

Add PrivateZoneID to the shared VKSLoadBalancerSpec, mapping to
LBC.Spec.PrivateZoneId (common.Zone) — identical to the Service controller's
private-zone-id annotation. Wire it in both the NLB and ALB applyLoadBalancerSpec
(PrivateSubnetID was already wired in both; leaving the new field unwired on ALB
would silently no-op). Regenerate deepcopy + both CRD copies.

Verified equivalent to the Service controller: scheme "InterVPC" matches
v2.InterVpcLoadBalancerScheme, and all three fields land on the same LBC the
LBC controller consumes.

Tests:
- unit: NLB TestApplyLoadBalancerSpec_InterVPC; extend ALB applyLoadBalancerSpec test
- envtest: NLB scenario mapping scheme/privateSubnet/privateZone onto the LBC

Docs: InterVPC section + example in the NLB guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vks-team vks-team changed the title feat(gateway-api): Phase 1 foundation (Sections A-E) feat(gateway-api): GEP-713 — Phase 1 (ALB) + Phase 2 (NLB/L4) Jun 12, 2026
anngdinh and others added 3 commits June 13, 2026 05:23
VKSBackendPolicy.TargetNodeLabels was wired into endpoint resolution on
both gateway paths but never asserted: existing tests mock the resolver
with mock.Anything for the variadic options, so the node selector built
from the labels was swallowed.

- NLB unit: TargetNodeLabels become an ANDed node selector passed to the
  resolver; no policy -> empty selector (all nodes).
- NLB e2e (opt-in, real cluster): selecting one node by hostname yields
  exactly one LB pool member with that node's IP. Skips on single-node.
- ALB unit: same wiring assertion via synthesizePool (helper alone was
  already covered by TestResolveTargetNodeLabels).

Test-only; no production code changed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… pattern

Document the GEP-713 direct-policy-attachment scope of the four CRDs and
its key consequence: VKSBackendPolicy/VKSHealthCheckPolicy attach to a
Service, so backend config is global to that Service across every Gateway
(mirrors upstream BackendTLSPolicy). Add the idiomatic recipe for fronting
one app with both an external and internal Gateway, and why differing
backend behaviour (e.g. targetType) per Gateway is modelled as two Services
rather than per-route backend policy. Cross-link from the NLB guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://vngcloud.github.io/vngcloud-load-balancer-controller/pr-preview/pr-9/

Built to branch gh-pages at 2026-06-25 04:12 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

anngdinh and others added 13 commits June 16, 2026 11:01
Default gatewayApi.alb.enabled to false and --disable-alb-gateway-controller
to true so the Helm chart installs cleanly on clusters that have not installed
the Gateway-API CRDs (GatewayClass/Gateway/HTTPRoute). NLB was already disabled.

Enabling stays one toggle (gatewayApi.alb.enabled=true) once the CRDs are present;
the deployment template already wires the flag from the value. Docs updated to
reflect the new defaults.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
….56.0

Bump the Go toolchain 1.25.10 -> 1.25.11 (go.mod, govulncheck workflow,
contributing docs).

Bump golang.org/x/net v0.54.0 -> v0.56.0 to fix GO-2026-5026 (idna ASCII-only
Punycode reject), which govulncheck reported as called from
pkg/utils/metadata/metadata_utils.go. go mod tidy pulled the companion x/
modules forward and promoted sigs.k8s.io/gateway-api to a direct require.

govulncheck ./... now reports 0 vulnerabilities affecting this code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route Gateway usecases through pkg/k8s.FinalizerManager, which re-Gets
the object before patching and swallows NotFound/Conflict, fixing the
StorageError (empty-UID precondition) when the Gateway is already gone.
Remove the now-dead internal/controller/gateway/shared finalizer helpers
and their tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Pool member weights set in LoadBalancerConfig (e.g. 80/20) were never
applied to the VNGCloud load balancer; traffic stayed 50/50.

Three causes in lbc_uc, all fixed:

- checkIfPoolMemberExist ignored weight, so a weight-only change was
  never detected and UpdatePoolMembers was never called. Weight is now
  part of member equality (via effectiveWeight, which treats nil/<=1 as
  the default weight of 1 to avoid a reconcile loop). Identity-only
  matching moved to a new checkIfPoolMemberExistByAddress, used for
  de-duplication and delete "can-cover" checks.

- Members were built with loadbalancerv2.NewMember, which hardcodes
  weight to 1. Replaced with buildMemberRequest, constructing the
  request struct directly with the member's weight (and backup) at all
  three call sites (deploy_pool create/update, delete_pool).

- mergePoolMembers kept the current (cloud) member for in-spec members,
  discarding the desired weight. It now prefers the spec member.

Adds unit tests covering weight-aware equality, identity matching,
weight-change detection, and spec-weight preference in merge.

Co-Authored-By: Claude <noreply@anthropic.com>
fix(lbc): apply pool member weight to load balancer
…enerics

golang/govulncheck-action installs @latest (v1.4.0), which links
x/tools@v0.46.0 whose SSA call-graph builder panics on generic code
under Go 1.25 ("ForEachElement called on type containing *types.TypeParam").
Invoke govulncheck directly pinned to v1.3.0 (x/tools@v0.44.0) instead.

Co-Authored-By: Claude <noreply@anthropic.com>
GitHub is deprecating Node 20 on Actions runners. Bump the SHA-pinned
actions that still target node20:

- actions/setup-go      v6.0.0  -> v6.5.0
- gitleaks/gitleaks-action  v2.3.9  -> v3.0.0
- docker/login-action       v3.4.0  -> v4.2.0
- docker/build-push-action  v6.16.0 -> v7.2.0

All bumps are runtime-only (node20 -> node24); inputs/outputs/behavior
are unchanged. The two env vars removed in build-push v7
(DOCKER_BUILD_NO_SUMMARY, DOCKER_BUILD_EXPORT_RETENTION_DAYS) are not
used in any workflow.

Co-Authored-By: Claude <noreply@anthropic.com>
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.

2 participants