Skip to content

Gateway status.addresses should fall back to publishService like the Ingress path #2800

Description

@joonslach

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions