diff --git a/.changelog/18291.txt b/.changelog/18291.txt new file mode 100644 index 000000000..bb0ec6f89 --- /dev/null +++ b/.changelog/18291.txt @@ -0,0 +1,3 @@ +```release-note:bug +api-gateway: fix race condition in proxy config generation when Consul is notified of the bound-api-gateway config entry before it is notified of the api-gateway config entry. +``` diff --git a/agent/proxycfg/api_gateway.go b/agent/proxycfg/api_gateway.go index 41eb59212..b4954cd39 100644 --- a/agent/proxycfg/api_gateway.go +++ b/agent/proxycfg/api_gateway.go @@ -54,12 +54,6 @@ func (h *handlerAPIGateway) initialize(ctx context.Context) (ConfigSnapshot, err return snap, err } - // Watch the bound-api-gateway's config entry - err = h.subscribeToConfigEntry(ctx, structs.BoundAPIGateway, h.service, h.proxyID.EnterpriseMeta, boundGatewayConfigWatchID) - if err != nil { - return snap, err - } - snap.APIGateway.Listeners = make(map[string]structs.APIGatewayListener) snap.APIGateway.BoundListeners = make(map[string]structs.BoundAPIGatewayListener) snap.APIGateway.HTTPRoutes = watch.NewMap[structs.ResourceReference, *structs.HTTPRouteConfigEntry]() @@ -143,10 +137,12 @@ func (h *handlerAPIGateway) handleRootCAUpdate(u UpdateEvent, snap *ConfigSnapsh return nil } -// handleGatewayConfigUpdate responds to changes in the watched config entry for a gateway. -// In particular, we want to make sure that we're subscribing to any attached resources such -// as routes and certificates. These additional subscriptions will enable us to update the -// config snapshot appropriately for any route or certificate changes. +// handleGatewayConfigUpdate responds to changes in the watched config entries for a gateway. +// Once the base api-gateway config entry has been seen, we store the list of listeners and +// then subscribe to the corresponding bound-api-gateway config entry. We use the bound-api-gateway +// config entry to subscribe to any attached resources, including routes and certificates. +// These additional subscriptions will enable us to update the config snapshot appropriately +// for any route or certificate changes. func (h *handlerAPIGateway) handleGatewayConfigUpdate(ctx context.Context, u UpdateEvent, snap *ConfigSnapshot, correlationID string) error { resp, ok := u.Result.(*structs.ConfigEntryResponse) if !ok { @@ -244,6 +240,12 @@ func (h *handlerAPIGateway) handleGatewayConfigUpdate(ctx context.Context, u Upd } snap.APIGateway.GatewayConfigLoaded = true + + // Watch the corresponding bound-api-gateway config entry + err := h.subscribeToConfigEntry(ctx, structs.BoundAPIGateway, h.service, h.proxyID.EnterpriseMeta, boundGatewayConfigWatchID) + if err != nil { + return err + } break default: return fmt.Errorf("invalid type for config entry: %T", resp.Entry)