Type
Feature request / behavior inconsistency between the Ingress and Gateway API reconcilers.
Current Behavior
In 2.1.0, the Gateway API controller populates Gateway.status.addresses only from gatewayProxy.spec.statusAddress. There is no fallback to publishService.
internal/controller/gateway_controller.go:
gatewayProxy, ok := tctx.GatewayProxies[rk]
if !ok {
acceptStatus = conditionStatus{status: false, msg: "gateway proxy not found"}
} else {
for _, addr := range gatewayProxy.Spec.StatusAddress { // only StatusAddress
addrType := gatewayv1.IPAddressType
if net.ParseIP(addr) == nil { addrType = gatewayv1.HostnameAddressType }
addrs = append(addrs, gatewayv1.GatewayStatusAddress{Type: &addrType, Value: addr})
}
}
...
gateway.Status.Addresses = addrs // overwrites; if StatusAddress is empty, addresses are cleared on every reconcile
By contrast, the Ingress controller already resolves publishService dynamically when statusAddress is not set.
internal/controller/ingress_controller.go (updateStatus):
// 1. use the IngressStatusAddress in the config
statusAddresses := gatewayProxy.Spec.StatusAddress
if len(statusAddresses) > 0 {
... // static
} else {
// 2. if the IngressStatusAddress is not configured, try to use the PublishService
publishService := gatewayProxy.Spec.PublishService
if publishService != "" {
... // resolves the LoadBalancer Service ingress IP/hostname dynamically
}
}
So publishService works for Ingress status but is ignored for Gateway status.
Expected Behavior
The Gateway reconciler should mirror the Ingress path: when gatewayProxy.spec.statusAddress is empty, fall back to gatewayProxy.spec.publishService and populate Gateway.status.addresses from that Service's .status.loadBalancer.ingress[].ip|hostname.
Why
On cloud LoadBalancers (we run OpenStack Octavia; AWS/GCP are equivalent), the external IP/hostname is assigned dynamically and can change when the LB is recreated. A static statusAddress is brittle: it must be hand-updated whenever the LB address changes, and if left empty the controller clears Gateway.status.addresses on every reconcile.
This breaks consumers that read Gateway.status.addresses — e.g. external-dns (--source=gateway-httproute) publishes A records from the Gateway address; an empty address causes it to remove all records for routes attached to the Gateway. publishService already exists on the GatewayProxy and is the natural dynamic source; it just isn't wired into the Gateway status path.
Environment
- apisix-ingress-controller
2.1.0 (manager), ADC 0.26.0
- Gateway API standalone mode,
gatewayProxy.spec.publishService set to the LoadBalancer Service, statusAddress unset
- LoadBalancer: OpenStack Octavia (dynamic VIP)
Proposed Change
In gateway_controller.go, after the StatusAddress loop, when no statusAddress entries are present, resolve gatewayProxy.spec.publishService to the Service's LoadBalancer ingress and append the resulting GatewayStatusAddress entries (IP → IPAddress, hostname → Hostname), reusing the helper logic already used by the Ingress path. Happy to contribute a PR if the direction is acceptable.
Related prior work: #2730 / #2732 (statusAddress hostname support + publishService/statusAddress logic).
Type
Feature request / behavior inconsistency between the Ingress and Gateway API reconcilers.
Current Behavior
In
2.1.0, the Gateway API controller populatesGateway.status.addressesonly fromgatewayProxy.spec.statusAddress. There is no fallback topublishService.internal/controller/gateway_controller.go:By contrast, the Ingress controller already resolves
publishServicedynamically whenstatusAddressis not set.internal/controller/ingress_controller.go(updateStatus):So
publishServiceworks for Ingress status but is ignored for Gateway status.Expected Behavior
The Gateway reconciler should mirror the Ingress path: when
gatewayProxy.spec.statusAddressis empty, fall back togatewayProxy.spec.publishServiceand populateGateway.status.addressesfrom that Service's.status.loadBalancer.ingress[].ip|hostname.Why
On cloud LoadBalancers (we run OpenStack Octavia; AWS/GCP are equivalent), the external IP/hostname is assigned dynamically and can change when the LB is recreated. A static
statusAddressis brittle: it must be hand-updated whenever the LB address changes, and if left empty the controller clearsGateway.status.addresseson every reconcile.This breaks consumers that read
Gateway.status.addresses— e.g. external-dns (--source=gateway-httproute) publishes A records from the Gateway address; an empty address causes it to remove all records for routes attached to the Gateway.publishServicealready exists on the GatewayProxy and is the natural dynamic source; it just isn't wired into the Gateway status path.Environment
2.1.0(manager), ADC0.26.0gatewayProxy.spec.publishServiceset to theLoadBalancerService,statusAddressunsetProposed Change
In
gateway_controller.go, after theStatusAddressloop, when nostatusAddressentries are present, resolvegatewayProxy.spec.publishServiceto the Service's LoadBalancer ingress and append the resultingGatewayStatusAddressentries (IP →IPAddress, hostname →Hostname), reusing the helper logic already used by the Ingress path. Happy to contribute a PR if the direction is acceptable.Related prior work: #2730 / #2732 (statusAddress hostname support + publishService/statusAddress logic).