{{/* HTTPRoute — the Gateway-API alternative to xxx.ingress.yaml (Gitea #114), and the reference implementation of that convention (README, "Ingress and Gateway API"). Copy this file with the rest of template-chart and rename it to .httproute.yaml. There is nothing chart-specific to replace in the body except the BACKEND: the Service name follows the naming scheme and the port below must be the port number your .service.yaml actually exposes. WHAT THIS RENDERS, AND WHAT IT MUST NOT Only an HTTPRoute with parentRefs. No Gateway, no gatewayClassName, no Certificate, and no implementation-specific policy object (ClientSettingsPolicy, ClientTrafficPolicy and their equivalents). That subset is the part which looks identical on nginx-gateway-fabric, Cilium, Envoy Gateway and Istio, and keeping to it is the whole reason the cluster's implementation can be chosen - or replaced - without touching the charts again. Adding a policy object here binds the chart to one implementation and to a CRD whose presence it cannot check. The consequence is that class and certificate belong to the PLATFORM: they sit on the Gateway and its listeners, in cluster-config. A chart in this mode renders no Certificate, so ingress.clusterIssuer does nothing - which is why it may only be `required` under ingress.enabled. WHAT HAS NO COUNTERPART AT ALL The Gateway API has no annotation channel for controller behaviour. Everything a chart does through ingress.annotations today - proxy-body-size, rewrite-target, external auth - is gone in this mode. rewrite-target has a real equivalent (the URLRewrite filter in a rule, not added here because this scaffold has no base path to strip); an upload limit does NOT, and a chart that depends on one must SAY SO in its NOTES.txt for this mode rather than quietly inherit the Gateway's default. WHY A VALUE AND NOT AUTO-DETECTION .Capabilities.APIVersions is unreliable at template time, and an HTTPRoute without the Gateway-API CRDs fails at install time. A chart that guessed would sometimes render an object the cluster rejects and sometimes silently render nothing at all. So the mode is a value, and the CRDs are the cluster's business. */}} {{- /* Null-safe like every other block a template here dereferences (#99): an override written without children - "httpRoute:" with its keys deleted - is YAML null, and `.Values.httpRoute.enabled` would abort with a nil pointer. An empty block means "chart defaults apply", and all three defaults are empty or false, so it collapses to "no HTTPRoute". */ -}} {{- $httpRoute := .Values.httpRoute | default dict -}} {{- if and $httpRoute.enabled .Values.ingress.enabled -}} {{- fail "ingress.enabled and httpRoute.enabled are both true - set exactly one of them. The Ingress and the HTTPRoute would publish the same Service under the same hostname over two different data paths, which is already a conflict at DNS level: one name, two addresses, and which one a client reaches is luck. A migration runs over a SECOND hostname (set httpRoute.hostnames explicitly while the Ingress keeps ingress.domain), never over parallel operation of both." -}} {{- end -}} {{- if $httpRoute.enabled -}} {{- $parentRefs := $httpRoute.parentRefs | default list -}} {{- if not $parentRefs -}} {{- fail "httpRoute.enabled is true but httpRoute.parentRefs is empty - an HTTPRoute without a parent attaches to no Gateway. It is created, it is schema-valid, and it routes NOTHING, with no event and no condition that says so; the only symptom is a hostname that does not answer. Name the cluster's Gateway, e.g. httpRoute.parentRefs: [{name: public, namespace: gateway}]." -}} {{- end -}} {{- /* One source of truth for the hostname: an empty httpRoute.hostnames means [ingress.domain]. Two values that have to agree drift apart. ingress.domain is read here although no Ingress is rendered in this mode - it names the public hostname of the release, which both modes need, and it is not an Ingress switch. In THIS chart that read is not even the only one: the env block in values.yaml reads ingress.domain too, which is why it carries a required() of its own and stays mandatory with the Ingress switched off (README, guideline 12, point 1). Check that per chart; do not copy the conclusion. */ -}} {{- $hostnames := $httpRoute.hostnames | default list -}} {{- if not $hostnames -}} {{- $hostnames = list (required "A Domain/Host must be provided: set ingress.domain (used as the HTTPRoute's single hostname when httpRoute.hostnames is empty) or set httpRoute.hostnames explicitly" .Values.ingress.domain) -}} {{- end -}} apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ .Release.Name }}-{{ .Chart.Name }}-httproute spec: parentRefs: {{- toYaml $parentRefs | nindent 4 }} hostnames: {{- toYaml $hostnames | nindent 4 }} rules: # The Ingress counterpart is `path: / , pathType: Prefix` on the backend # Service. The port is the Service's port NUMBER, not its name: # backendRefs takes a PortNumber, so unlike the Ingress this reference # cannot be made by name, and the number here has to track # .service.yaml by hand. ci/run-httproute-match-test.sh is what holds # that pair - it fails when a backendRef names a Service, or a port, that # the same render does not create. - matches: - path: type: PathPrefix value: / backendRefs: - name: {{ .Release.Name }}-{{ .Chart.Name }}-service port: 80 {{- end }}