docs/rfc/0007-gateway-api-route-provider.md
Add first-class, provider-pluggable route exposure to the Fission router.
Today the router can create a networking.k8s.io/Ingress per HTTPTrigger (--createIngress).
Ingress is frozen and the ecosystem is moving to the Gateway API (gateway.networking.k8s.io).
This RFC introduces an internal RouteProvider abstraction, ships a Gateway-API provider that
emits HTTPRoute objects attached to an operator-managed Gateway, refactors the existing
Ingress code into an ingress provider behind the same interface, and marks the Ingress
integration deprecated.
ingress-nginx is in maintenance and many operators are migrating to Gateway API
implementations (Envoy Gateway, Istio, Cilium, Contour, NGINX Gateway Fabric).HTTPRoute v1).HTTPRoute objects out-of-band, decoupling
them from the HTTPTrigger lifecycle (no create/update/delete coupling, no status).HTTPRoute objects, lifecycle-coupled to the HTTPTrigger.HTTPRoute with a parentRef to a Gateway the operator owns.CreateIngress + IngressConfig keep working, now marked
deprecated.gateway.networking.k8s.io RBAC; disabled by default, no behavior change for existing users.Gateway or GatewayClass (listeners/TLS are the operator's
responsibility). This keeps RBAC minimal and avoids coupling to listener config.rfc/README.md).TCPRoute/GRPCRoute/TLSRoute (HTTP functions only, for now).pkg/router/)type RouteProvider interface {
Name() string // "ingress" | "gateway"
// Reconcile creates/updates the route when the trigger requests THIS provider,
// and deletes any object this provider owns for the trigger otherwise — so every
// registered provider sees every trigger and self-cleans on provider switch / toggle-off.
Reconcile(ctx context.Context, trigger *fv1.HTTPTrigger) error
// DeleteByName removes any object this provider owns for a deleted trigger (idempotent).
DeleteByName(ctx context.Context, name string) error
}
httpTriggerReconciler holds providers []RouteProvider. Its Reconcile loops the providers
(replacing the single reconcileIngress call); the delete path loops DeleteByName.RouteConfig.Provider if set; else legacy CreateIngress ⇒
"ingress"; else none. Each provider checks "am I the desired provider & is exposure
requested?" → reconcile, else → delete-own. This reuses the toggle-off / provider-switch
semantics the current reconcileIngress already has.ingress provider is the current reconcileIngress/deleteIngressByName/GetIngressSpec
moved behind the interface — no behavior change; it also serves legacy CreateIngress.gateway provider is registered only when GATEWAY_API_ENABLED is set, so an absent
provider (no RBAC) surfaces as a clear HTTPTrigger status condition rather than RBAC errors.pkg/router/gatewayapi.go + util.GetHTTPRouteSpec(namespace, trigger, defaultParentRefs) →
gwapiv1.HTTPRoute:
ParentRefs from RouteConfig.Gateway.ParentRefs, falling back to the Helm-configured default
Gateway parentRef when the trigger omits it.Hostnames from RouteConfig.Hostnames.PathPrefix/Exact match from RouteConfig.Path (default /); BackendRefs →
router Service:80 (the same backend Ingress uses); annotations + GetDeployLabels labels.HTTPRoute.sigs.k8s.io/gateway-api/pkg/client/clientset/versioned clientset, doing
direct API create/update/delete (mirrors how the Ingress provider uses kubernetes.Interface —
no Manager cache informer for HTTPRoute). Reached via crd.ClientGenerator.GetGatewayClient().pkg/apis/core/v1/types.go)New provider-neutral field on HTTPTriggerSpec (successor to CreateIngress + IngressConfig):
RouteConfig *RouteConfig `json:"routeConfig,omitempty"`
type RouteConfig struct {
Provider string `json:"provider"` // +kubebuilder:validation:Enum=ingress;gateway
Hostnames []string `json:"hostnames,omitempty"`
Path string `json:"path,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
TLS string `json:"tls,omitempty"` // ingress-only; ignored by gateway
Gateway *GatewayRouteConfig `json:"gateway,omitempty"`
}
type GatewayRouteConfig struct { ParentRefs []GatewayParentRef `json:"parentRefs,omitempty"` }
type GatewayParentRef struct {
Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
SectionName string `json:"sectionName,omitempty"`
Port int32 `json:"port,omitempty"`
}
CreateIngress + IngressConfig are marked // Deprecated: (kept functional).+kubebuilder:validation:XValidation mirrors the IngressConfig rules (path absolute, host
DNS1123). Go RouteConfig.Validate() is added and called from HTTPTriggerSpec.Validate.charts/fission-all/)values.yaml: gatewayAPI.enabled: false (+ optional gatewayAPI.defaultParentRef)._fission-kubernetes-roles.tpl): when enabled, add
gateway.networking.k8s.io/httproutes (create/get/list/watch/update/patch/delete) and read-only
referencegrants.GATEWAY_API_ENABLED (+ default parentRef) env, following the existing
enableIstio / feature-config plumbing.pkg/fission-cli/)New httptrigger flags: --route-provider (ingress|gateway), --route-host (repeatable),
--route-path, --gateway/--gateway-parentref name[.namespace], --route-annotation,
--route-tls. GetRouteConfig builds *RouteConfig (analogous to GetIngressConfig).
Legacy --createingress* flags are kept with deprecation notes in their usage; if both are passed,
RouteConfig wins.
--gatewayApi subsystem. Rejected: Ingress reconciliation already lives in the
router tied to HTTPTrigger; a new process/flag/leader-election adds operational surface for no
benefit.CreateIngress/IngressConfig and all --ingress* CLI flags continue to work unchanged.+optional; old clients and stored objects round-trip.sigs.k8s.io/gateway-api dep; register gwapiv1 into the router scheme. (compiles, inert)RouteConfig types + deprecate Ingress fields + CEL + RouteConfig.Validate; codegen +
generate-crds; validation unit tests.RouteProvider abstraction; extract Ingress into the ingress provider; reconciler loops
providers. Pure refactor — existing router tests stay green.gatewayapi.go + GetHTTPRouteSpec + GetGatewayClient wiring; provider
registered on GATEWAY_API_ENABLED; unit tests.gatewayAPI.enabled value, RBAC, deployment env.GetRouteConfig + create/update; deprecate legacy ingress flag usage strings.make codegen && make generate-crds clean; make license-check.GetHTTPRouteSpec, RouteConfig.Validate, provider switch/toggle-off/delete semantics
(table-driven, testify, t.Context()).RouteConfig round-trips; CEL rejects bad path/host.GatewayClass+Gateway, create a
gateway-provider HTTPTrigger, confirm Fission creates the HTTPRoute, it attaches
(Accepted/ResolvedRefs), curling the Gateway routes to the function, and toggling
provider/deleting the trigger removes the HTTPRoute.test/integration/suites/common/, t.Skip when no Gateway
controller present.Path: PathPrefix (Ingress-like) vs Exact. Proposed: PathPrefix,
overridable later.RouteConfig.Provider default to gateway when GATEWAY_API_ENABLED and a default
parentRef is configured, so --route-host alone is enough? Proposed: require explicit provider
for now.HTTPRoute → Gateway needs a ReferenceGrant in the Gateway's namespace,
owned by the operator. Document only; Fission does not create grants.