From 23d4b81bef31745f4dcf7d54e40a6e7eb3c5e452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 16 Dec 2024 08:09:37 +0100 Subject: [PATCH 01/44] feat: :package: add separated chart for CRDs --- README.md | 2 +- hack/test.sh | 1 + traefik-crds/.helmignore | 23 ++++++++ traefik-crds/Chart.yaml | 23 ++++++++ .../gateway}/gateway-standard-install.yaml | 0 .../hub.traefik.io_accesscontrolpolicies.yaml | 0 .../hub}/hub.traefik.io_aiservices.yaml | 0 .../hub}/hub.traefik.io_apiaccesses.yaml | 0 .../hub}/hub.traefik.io_apibundles.yaml | 0 .../hub}/hub.traefik.io_apicatalogitems.yaml | 0 .../hub}/hub.traefik.io_apiplans.yaml | 0 .../hub}/hub.traefik.io_apiportals.yaml | 0 .../hub}/hub.traefik.io_apiratelimits.yaml | 0 .../crds-files/hub}/hub.traefik.io_apis.yaml | 0 .../hub}/hub.traefik.io_apiversions.yaml | 0 .../hub.traefik.io_managedsubscriptions.yaml | 0 .../traefik}/traefik.io_ingressroutes.yaml | 0 .../traefik}/traefik.io_ingressroutetcps.yaml | 0 .../traefik}/traefik.io_ingressrouteudps.yaml | 0 .../traefik}/traefik.io_middlewares.yaml | 0 .../traefik}/traefik.io_middlewaretcps.yaml | 0 .../traefik.io_serverstransports.yaml | 0 .../traefik.io_serverstransporttcps.yaml | 0 .../traefik}/traefik.io_tlsoptions.yaml | 0 .../traefik}/traefik.io_tlsstores.yaml | 0 .../traefik}/traefik.io_traefikservices.yaml | 0 traefik-crds/kustomization.yaml | 27 +++++++++ traefik-crds/templates/crds.yaml | 42 ++++++++++++++ traefik-crds/tests/crds_test.yaml | 53 ++++++++++++++++++ traefik-crds/values.yaml | 3 + traefik/Chart.lock | 6 ++ traefik/Chart.yaml | 4 ++ traefik/charts/traefik-crds-0.0.1.tgz | Bin 0 -> 125870 bytes traefik/values.schema.json | 20 +++++++ traefik/values.yaml | 8 +++ 35 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 traefik-crds/.helmignore create mode 100644 traefik-crds/Chart.yaml rename {traefik/crds => traefik-crds/crds-files/gateway}/gateway-standard-install.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_accesscontrolpolicies.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_aiservices.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apiaccesses.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apibundles.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apicatalogitems.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apiplans.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apiportals.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apiratelimits.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apis.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_apiversions.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/hub}/hub.traefik.io_managedsubscriptions.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_ingressroutes.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_ingressroutetcps.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_ingressrouteudps.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_middlewares.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_middlewaretcps.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_serverstransports.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_serverstransporttcps.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_tlsoptions.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_tlsstores.yaml (100%) rename {traefik/crds => traefik-crds/crds-files/traefik}/traefik.io_traefikservices.yaml (100%) create mode 100644 traefik-crds/kustomization.yaml create mode 100644 traefik-crds/templates/crds.yaml create mode 100644 traefik-crds/tests/crds_test.yaml create mode 100644 traefik-crds/values.yaml create mode 100644 traefik/Chart.lock create mode 100644 traefik/charts/traefik-crds-0.0.1.tgz diff --git a/README.md b/README.md index 635e64d10..34c898ef5 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ helm repo update # See current Chart & Traefik version helm search repo traefik/traefik # Update CRDs (Traefik Proxy v3 CRDs) -kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik/crds/ +kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik-crds/ # Upgrade Traefik helm upgrade traefik traefik/traefik ``` diff --git a/hack/test.sh b/hack/test.sh index e71504fb1..49933bd06 100644 --- a/hack/test.sh +++ b/hack/test.sh @@ -1,3 +1,4 @@ #!/bin/bash /usr/bin/helm unittest --color ./traefik; +/usr/bin/helm unittest --color ./traefik-crds; diff --git a/traefik-crds/.helmignore b/traefik-crds/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/traefik-crds/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/traefik-crds/Chart.yaml b/traefik-crds/Chart.yaml new file mode 100644 index 000000000..ac4dc30f9 --- /dev/null +++ b/traefik-crds/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: traefik-crds +description: A Traefik based Kubernetes ingress controller +type: application +version: 0.0.1 +kubeVersion: ">=1.22.0-0" +keywords: + - traefik + - ingress + - networking +home: https://traefik.io/ +sources: + - https://github.com/traefik/traefik + - https://github.com/traefik/traefik-helm-chart +maintainers: + - name: mloiseleur + email: michel.loiseleur@traefik.io + - name: charlie-haley + email: charlie.haley@traefik.io + - name: darkweaver87 + email: remi.buisson@traefik.io + - name: jnoordsij +icon: https://raw.githubusercontent.com/traefik/traefik/v2.3/docs/content/assets/img/traefik.logo.png diff --git a/traefik/crds/gateway-standard-install.yaml b/traefik-crds/crds-files/gateway/gateway-standard-install.yaml similarity index 100% rename from traefik/crds/gateway-standard-install.yaml rename to traefik-crds/crds-files/gateway/gateway-standard-install.yaml diff --git a/traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml diff --git a/traefik/crds/hub.traefik.io_aiservices.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_aiservices.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_aiservices.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_aiservices.yaml diff --git a/traefik/crds/hub.traefik.io_apiaccesses.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apiaccesses.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apiaccesses.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apiaccesses.yaml diff --git a/traefik/crds/hub.traefik.io_apibundles.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apibundles.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apibundles.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apibundles.yaml diff --git a/traefik/crds/hub.traefik.io_apicatalogitems.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apicatalogitems.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apicatalogitems.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apicatalogitems.yaml diff --git a/traefik/crds/hub.traefik.io_apiplans.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apiplans.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apiplans.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apiplans.yaml diff --git a/traefik/crds/hub.traefik.io_apiportals.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apiportals.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apiportals.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apiportals.yaml diff --git a/traefik/crds/hub.traefik.io_apiratelimits.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apiratelimits.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apiratelimits.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apiratelimits.yaml diff --git a/traefik/crds/hub.traefik.io_apis.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apis.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apis.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apis.yaml diff --git a/traefik/crds/hub.traefik.io_apiversions.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_apiversions.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_apiversions.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_apiversions.yaml diff --git a/traefik/crds/hub.traefik.io_managedsubscriptions.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_managedsubscriptions.yaml similarity index 100% rename from traefik/crds/hub.traefik.io_managedsubscriptions.yaml rename to traefik-crds/crds-files/hub/hub.traefik.io_managedsubscriptions.yaml diff --git a/traefik/crds/traefik.io_ingressroutes.yaml b/traefik-crds/crds-files/traefik/traefik.io_ingressroutes.yaml similarity index 100% rename from traefik/crds/traefik.io_ingressroutes.yaml rename to traefik-crds/crds-files/traefik/traefik.io_ingressroutes.yaml diff --git a/traefik/crds/traefik.io_ingressroutetcps.yaml b/traefik-crds/crds-files/traefik/traefik.io_ingressroutetcps.yaml similarity index 100% rename from traefik/crds/traefik.io_ingressroutetcps.yaml rename to traefik-crds/crds-files/traefik/traefik.io_ingressroutetcps.yaml diff --git a/traefik/crds/traefik.io_ingressrouteudps.yaml b/traefik-crds/crds-files/traefik/traefik.io_ingressrouteudps.yaml similarity index 100% rename from traefik/crds/traefik.io_ingressrouteudps.yaml rename to traefik-crds/crds-files/traefik/traefik.io_ingressrouteudps.yaml diff --git a/traefik/crds/traefik.io_middlewares.yaml b/traefik-crds/crds-files/traefik/traefik.io_middlewares.yaml similarity index 100% rename from traefik/crds/traefik.io_middlewares.yaml rename to traefik-crds/crds-files/traefik/traefik.io_middlewares.yaml diff --git a/traefik/crds/traefik.io_middlewaretcps.yaml b/traefik-crds/crds-files/traefik/traefik.io_middlewaretcps.yaml similarity index 100% rename from traefik/crds/traefik.io_middlewaretcps.yaml rename to traefik-crds/crds-files/traefik/traefik.io_middlewaretcps.yaml diff --git a/traefik/crds/traefik.io_serverstransports.yaml b/traefik-crds/crds-files/traefik/traefik.io_serverstransports.yaml similarity index 100% rename from traefik/crds/traefik.io_serverstransports.yaml rename to traefik-crds/crds-files/traefik/traefik.io_serverstransports.yaml diff --git a/traefik/crds/traefik.io_serverstransporttcps.yaml b/traefik-crds/crds-files/traefik/traefik.io_serverstransporttcps.yaml similarity index 100% rename from traefik/crds/traefik.io_serverstransporttcps.yaml rename to traefik-crds/crds-files/traefik/traefik.io_serverstransporttcps.yaml diff --git a/traefik/crds/traefik.io_tlsoptions.yaml b/traefik-crds/crds-files/traefik/traefik.io_tlsoptions.yaml similarity index 100% rename from traefik/crds/traefik.io_tlsoptions.yaml rename to traefik-crds/crds-files/traefik/traefik.io_tlsoptions.yaml diff --git a/traefik/crds/traefik.io_tlsstores.yaml b/traefik-crds/crds-files/traefik/traefik.io_tlsstores.yaml similarity index 100% rename from traefik/crds/traefik.io_tlsstores.yaml rename to traefik-crds/crds-files/traefik/traefik.io_tlsstores.yaml diff --git a/traefik/crds/traefik.io_traefikservices.yaml b/traefik-crds/crds-files/traefik/traefik.io_traefikservices.yaml similarity index 100% rename from traefik/crds/traefik.io_traefikservices.yaml rename to traefik-crds/crds-files/traefik/traefik.io_traefikservices.yaml diff --git a/traefik-crds/kustomization.yaml b/traefik-crds/kustomization.yaml new file mode 100644 index 000000000..3806a9de8 --- /dev/null +++ b/traefik-crds/kustomization.yaml @@ -0,0 +1,27 @@ +--- +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +resources: + # curl -o crds-files/gateway/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml + - crds-files/gateway/gateway-standard-install.yaml + - crds-files/hub.traefik.io_accesscontrolpolicies.yaml + - crds-files/hub.traefik.io_aiservices.yaml + - crds-files/hub.traefik.io_apiaccesses.yaml + - crds-files/hub.traefik.io_apibundles.yaml + - crds-files/hub.traefik.io_apicatalogitems.yaml + - crds-files/hub.traefik.io_apiplans.yaml + - crds-files/hub.traefik.io_apiportals.yaml + - crds-files/hub.traefik.io_apiratelimits.yaml + - crds-files/hub.traefik.io_apis.yaml + - crds-files/hub.traefik.io_apiversions.yaml + - crds-files/hub.traefik.io_managedsubscriptions.yaml + - crds-files/traefik/traefik.io_ingressroutes.yaml + - crds-files/traefik/traefik.io_ingressroutetcps.yaml + - crds-files/traefik/traefik.io_ingressrouteudps.yaml + - crds-files/traefik/traefik.io_middlewares.yaml + - crds-files/traefik/traefik.io_middlewaretcps.yaml + - crds-files/traefik/traefik.io_serverstransports.yaml + - crds-files/traefik/traefik.io_serverstransporttcps.yaml + - crds-files/traefik/traefik.io_tlsoptions.yaml + - crds-files/traefik/traefik.io_tlsstores.yaml + - crds-files/traefik/traefik.io_traefikservices.yaml diff --git a/traefik-crds/templates/crds.yaml b/traefik-crds/templates/crds.yaml new file mode 100644 index 000000000..84dcf5a01 --- /dev/null +++ b/traefik-crds/templates/crds.yaml @@ -0,0 +1,42 @@ +{{- if .Values.traefik -}} +{{- $files := .Files }} +{{- range tuple +"crds-files/traefik/traefik.io_ingressroutes.yaml" +"crds-files/traefik/traefik.io_ingressroutetcps.yaml" +"crds-files/traefik/traefik.io_ingressrouteudps.yaml" +"crds-files/traefik/traefik.io_middlewares.yaml" +"crds-files/traefik/traefik.io_middlewaretcps.yaml" +"crds-files/traefik/traefik.io_serverstransports.yaml" +"crds-files/traefik/traefik.io_serverstransporttcps.yaml" +"crds-files/traefik/traefik.io_tlsoptions.yaml" +"crds-files/traefik/traefik.io_tlsstores.yaml" +"crds-files/traefik/traefik.io_traefikservices.yaml" + }} +{{ $files.Get . }} +{{- end }} +{{- end }} + +{{- if .Values.hub -}} +{{- $files := .Files }} +{{- range tuple +"crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml" +"crds-files/hub/hub.traefik.io_apiaccesses.yaml" +"crds-files/hub/hub.traefik.io_apibundles.yaml" +"crds-files/hub/hub.traefik.io_apiplans.yaml" +"crds-files/hub/hub.traefik.io_apiportals.yaml" +"crds-files/hub/hub.traefik.io_apiratelimits.yaml" +"crds-files/hub/hub.traefik.io_apis.yaml" +"crds-files/hub/hub.traefik.io_apiversions.yaml" + }} +{{ $files.Get . }} +{{- end }} +{{- end }} + +{{- if .Values.gateway_api -}} +{{- $files := .Files }} +{{- range tuple +"crds-files/gateway/gateway-standard-install-v1.1.0.yaml" + }} +{{ $files.Get . }} +{{- end }} +{{- end }} diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml new file mode 100644 index 000000000..deeef0b22 --- /dev/null +++ b/traefik-crds/tests/crds_test.yaml @@ -0,0 +1,53 @@ +suite: CRDs +templates: + - crds.yaml +tests: + - it: shouldn't have any crds by default + asserts: + - hasDocuments: + count: 0 + + - it: should have all Traefik crds + set: + traefik: true + asserts: + - hasDocuments: + count: 10 + - isKind: + of: CustomResourceDefinition + - equal: + path: spec.group + value: traefik.io + - matchRegex: + path: spec.names.kind + pattern: ^(IngressRoute|IngressRouteTCP|IngressRouteUDP|Middleware|MiddlewareTCP|ServersTransport|ServersTransportTCP|TLSOption|TLSStore|TraefikService)$ + + - it: should have all Traefik Hub crds + set: + hub: true + asserts: + - hasDocuments: + count: 8 + - isKind: + of: CustomResourceDefinition + - equal: + path: spec.group + value: hub.traefik.io + - matchRegex: + path: spec.names.kind + pattern: ^(AccessControlPolicy|APIAccess|APIBundle|APIPlan|APIPortal|APIRateLimit|API|APIVersion)$ + + - it: should have all Gateway API crds + set: + gateway_api: true + asserts: + - hasDocuments: + count: 5 + - isKind: + of: CustomResourceDefinition + - equal: + path: spec.group + value: gateway.networking.k8s.io + - matchRegex: + path: spec.names.kind + pattern: ^(GatewayClass|Gateway|GRPCRoute|HTTPRoute|ReferenceGrant)$ diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml new file mode 100644 index 000000000..6daca116a --- /dev/null +++ b/traefik-crds/values.yaml @@ -0,0 +1,3 @@ +traefik: false +gateway_api: false +hub: false diff --git a/traefik/Chart.lock b/traefik/Chart.lock new file mode 100644 index 000000000..7a83ae7bb --- /dev/null +++ b/traefik/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: traefik-crds + repository: file://../traefik-crds + version: 0.0.1 +digest: sha256:03a8641bfa1d261b699d166dea5aaa21d9e27bfc2328d157dae3809375709260 +generated: "2024-10-11T17:04:46.473483814+02:00" diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 668303cf1..91af7b126 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -27,3 +27,7 @@ annotations: artifacthub.io/changes: | - "fix(Gateway API): CRDs should only be defined once" - "chore(release): 🚀 publish v33.2.1" +dependencies: + - name: traefik-crds + version: "0.0.1" + repository: "file://../traefik-crds" diff --git a/traefik/charts/traefik-crds-0.0.1.tgz b/traefik/charts/traefik-crds-0.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..81b81708ab0708c9690920b0da69b75c9afef055 GIT binary patch literal 125870 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

cGY4Vk6_fP6aP@xuLYlNujY5k*1$SN zZjtMClnICZ@LpC>DLgx=VwLlFe*YT?n={^d45*~fU6P&6 zeGlsgAt-4v21fp~x?7vEN9Sy;z0yQdW?B*TJ_uB&;SJSBW+6KEALlXu5@|;PqVtcx zfBgck%c`|0Qf3C)hD+CH-aCD0(3$F}o!^=&r7H^^h}7f^Xuw}BH`ijp(5i~Co`W1S z96fYww9pF8E;+|`x~)~q#NY)5NA*dDEy4IsO0&Rf)p;`BZs$%GuKW8&nunZOr}#nl zxgZ*hJ_`&}&_1Zm(*f4Afm@JR;CiRs%1`xMFMYilwJ_=ZmT>D-|1jeWBYur_;tc9L ziLDpO>WTfqjfCiaG0QH5l_&Q}F;3sWVVN&ii|4oH)UTPQ3`Dghs|3^_V z>pG_aH1uB?!oOzQa=o45>Y>^MFll8z0q(va5<*D-WGrV6271D`c>h{Z>VpELHN)Ke z8^O-~tktBfsT}wQUg`fb46TRbI@TbT*k% z`02{p8_k6O@+V%0F74;IUvHUJxc`bWwAl6by}53xQs$JM;y6nHM)e!ikYOh;C?7>r zW?X&`TpN266>z0J;8%8inQm^28D>~~SgBD+>G<#$XuMQ5Tlp+QH-Nw7e9*m^eWFL> ziInxJi~rFdKBD&3(#BnbsP9f+|Fp1|*tjX$M~#KD+;9cjm@Vm+%=Eh}N{YVN{4+w- z?)@6EPn{D)!5W}?t+}L`-zHBZ!qZ%6>~17pOEY438U{EB2luos#amP|WqS2pVKtAW zjb*)rQsr2}Oh)7Li+x|X{>+KN?q(suNz1cC$*U<}AfjhrrhA?Rt-q(=yVc{ z#zGT&Om~O8w`JGA)L-&dNkzN{c()C|65Y3vh-b1=??OL)*h_i5FKr8BKRMGzzgUj< zTK4L3KTl?BKP_Ghrr|Kr-e+vECv+EgRy2Y}AeAtr^86mXH97|OO_mx4Gji~bcAsQ@IODi1rucWkfocNgDpM%7AbB9z{$q0 zt!1$|WP??R_V(`?A=bBVsY13s{a-xYQ(#@ex&YwDO=BC4ZQHhOyRmKCwrw@GZQD-c zyW4Zl-7mw}wf3xkX1>2<9C=U1T%!JuHC46YJT>+S{DL^+D86IznDF*$Ck;zD(3zTz zNW~AFVV|0l@^|BnA_}LfWtQ%s2>?b)ef~B zU($>_8uLqumFiiOwfg$qEyn|W0uTARIb?}VT__yr1Hq;nSrJvL67p1bu7iK2M`wWa z2(#b|d0M*|*~ys^L58^ePkQ{^e^-cFh=$M_D1MkL++i-ms(T%0j>v~3v-9#VR-$Cz z_?6A0ggKg+d0MK0Da>lrC^oid_D1I z7tT$oYs#)qB_2owv1fRY0&Oxe@VTrtzwJboaoI97nBHW6Sc8s2*gqRnh-&DwZZUkS z`khIAweG12s`RvpDmvh3t1%cW?{p}ig7e*VrAvnnNm+-&NW9t=uULM6^3;+d@ibx- zqnZlT^fFG@9Q*T!;Y>#^T>l@b^9z9WxR&Yi|JLJ{pXEouk{qxVPT=GiM(zFn@6PER z&zRSY;0?xB#O{2ET0b@vs}V6NDZ>1F_IdvA)dwuJQI-it@B4k$$%q3pDgq_eEoxw} z94)CZUPsPos0Ejr5m!?Rj%X_R&QP;Y#JYInbD%TB?p+t-Y+Y3%Vo#(57e7xOZH_)b zbP;|x+cgF-0wW@Wl}xyZD^)wRp*!FI?y zeV>;LEc?I+r(@<7L@2H{CF^5C1`v_51BDF8`sF-=2qbUNCW*a~45{)K*}ai-cYxNK zDP2J$cL2uWK5M}PLB1{U5l0C-k=9-8pgF9Ffjv#smlk}xhA^w5eWBl9>G9+MyFVwK&YYi z5paNtebAJ{rf3jdECPLznF^DuB<*Ty?df4+Boi4wy_`N1vFKJV%Avm$ysu$yTb|Ch z>KGTtzJXxk4dx=L-`Wd(^}>V@BbmhA;Sqb3s1O8_C&a-T7#j4N&IPnxn05m&FHAbz zJ7bo6WD0BWggy%Dfp?UsAq2NnW+L$XNv98ob!qr&<6n|D02HdfQGL*3e53^r_(WTg`D$CO?GEMhxL~N9~gD3h(gKV?2WAM4T!!cB* z_mgK>9w^)A2^|J0(t$Tzd9ntqAAAqSGGag(@76lCiNY)v6=AYYA$YLs@QB7pkwN2{ zTNLMey$5&n>ety~Nm8 zbPXAnp1x_1Z+~CxfZ^-^OuW2$12oS6(>OBqO~cVM;r)@iiVM7~dgB54j{8wfxr5U@ zgKsOIm9SJVIpH-S;(0Z|AT=qXh`H!aqc@40bIAd%Fh7-D^?5c*l=IVJfvKsXVR;b4 zOMF>Wj(oAoS&K&cWAte?`1Hwj-m&6;&ZFG0qZ3TkxRaB$b%5u`OLcRbCgYZf*|Y0@ zqeH%+R&>QKDIN)x82fZ;g2-v`Hk!FotoolmaMEm1n5iy*;~)Dgu~y|-kNd;8f1yV! z_Hzo!KUM`p0n?nNrE%m^P$Ukci#pGt#a2Lmwg{JBXo}rXFs=O~y7(PNk`>YWRB2=GqO*HMLq^CZ*f2$>qa2 ze=j1oO#JzEjp1Qx_wqmK(SPe;v;{kJHiAjp4-!og>=lZCVB&2iRTxd|$N z*?(N=YHGO9?2#;DW{N)DxYD+^)|OMn5&w`yY}FZs+K8bt6(W{=3R@&hI#ER3r*0!d z;uCBAvbZM)&t)JQm1N0&d39*Qf|f=zT_el6scEsEt37Fy4dHk_J*0t|g*j+k$f&}3 z);4ZW^pcPKW20}oB3fFDJ(8e?5GYLi(06c_81*=9h^h;9R1;TMX8W@w)1Lm!{*2#F z6BY28Yq1A%4Mb+ z{7U^5!v#Be_GR{nAjUKv@7uehfstSE5r5=&qQzCsoF@dbN=0aAYJyq=nM0E-`vwbvwvIL14zQU>jDyfmM z!+UnPda^+>!<*pwv=J_YFNI{PB8zQtP%y6FSOSFPdbt{<;v5huT~n)aU#EU~&j&Tr zB+sx{I5JmWkB3M+15&ieMBp5B0~} zu7b`EZM-K{E5e%h(Nyj$G~u0!YT;p&q6uHKz^7(+yecH8Ut4b`gaT!p6=nFQ>Ata* zBP)pyPbBIwZeu7guTss5rQJ+X?L@tJOxh+)uH$=l8tjNp!aN8wG@>FG&ha_%+7met zGJZxyGMo}xy%xL0^&sTVNpMXCq!KdH7WdDPQHqyYO4jJhraFTPE}74XKLiTIwEES& z#OnydTBDf_AcWZ4CMhA^hv=pY*czjs0MesCvI6cSiV>cQ71J3#76SU_qVn56>2YEc zGEK@YGGb@RND55ps2`mro03-htdxAoq7A{2Tgw|1UQ3jA4x%6V7b!;rJuroIcaWx_ zf@(>B^9FC!u2hJfRJvBZl4^t1wGg?XD{6Y!_^%`tN$)nXO@(Syp%tlSMlJq|z~G6{ zAG5DXK0y7r#!%c5D6gm=Z6@Ii**{!8Qa;$;Nl#h__A7)+5BJbn&HXSMZA=9;apIPo zQkqC7+cX$yezKBCVwjb)J%4DYQUCO#4u6oH+gWgI{G@L79y>y;FL=7Kfsb&#!;%by zH4CDSr9cE?Y3j^|RCV?r3G(RS@!uqG7KK11)sFk>^K3=ZYycr;0>^#uWix}0kq z=WimbJzS`aY3^36HxSR&=`aGP4aMK&;GjcpQuZ(mJ|Fqao(;vu#dgFa9CnbhLabZF z2_K=h5aJ?+DhCBPk2FXkiUkCCk;<}PTTTGykx06LTw_ZyE($&Mg&)K>32WS{a+R7AJP~TdqW$QY7t_wZuS59p&GsPVE8>Vp zrc4xA>^j&VtdOVzVy!_3g1&A1!)Jx^n7?90SPkRp24Aet=%ap;I+-vr6xEeE+eh+C zZ}<)^RT?6a@O^(hsy+Fo$j!C#K1!kg>NrjhGs!h1M%82fgFqzVWN6DpOStH@*WXBvi2t<1+Xutvn2AS8NBpvcfQ#`vSVh=5FIjw+eFu8#bN4e zf6A`=^Ndc$Aq^A}k~rags`mg>VP^?TO|s~XL$bSnc7D4tn@!d>;#X@&Bu|&!7e}+v zVpPi)O&|s_Kv;p5tyar5BrE_tpT$c6=20^`b?hMB+&Os5G64p*?AX0TbKokGHjU}k zN@kQQIyEt{OH-I@#~jM#j_m+Q+Mz?*rS7_btlsEb`ftrTeBtnZTyl~#Moe@&o(%VD+mz*Ea%={4gzUZA&l>;--BoSn(FWf z9pzg^JV)z9YnefnDBQp`NMmry!-P(UO{lT3TvBpf&3ih9`SR)9{LrHHdW`4BxQ{?t zobC1P!2rtRL-2}Dbk?q=@IfD&s1iVVy!;^||5tfDKf0mob3)d>`Msvu0}(}M8E?h> zPkA(MB*!5wGDD-Qh}vDlGbrP#n=5|>vENjWS3AfGI@U-E_UkhUkC7MREDGoQ zLJ5vur`IxsUcE%DCsCvyD*bSljse+jb2&*KadRG5-lO$MG5z|$k*l{7rWnxEp6hGa zW7646kGsuYxy~Ou5C~Gv1+cbXjKdXbK3_=3WYEg<_02;Td31VLPWM3;mE=S2nTYKg zb!?!&L8ENHgX&N^Y3z5)kqh^511p7<$tI=ffF(cnXPy2(^LU|XGZTR`QY8V+F$gxy z_?n^X*UM7`#>&4^hpT;DvIPeAAqjc*LrJILih|%o8?%`T`=^42}k*z4evW7i|~$#lt#ebtjy0F-_JdVo!og69>n z;HCGxwt!kO|9&uymN*BsZ#Wj%Y5~?C%t0G@EykS4ACIYuY=z{~NSK|*;@*Idj@skf zu8NmXTp(*K|&y$oG>9S{{ zoEDaC$;9nEyM_I;0nd91vTa?fth&Td%4FYpwf5)NcbUtvhJ13ps*W$w=9U%*>gVdO z-*J{NqOQc-Cr3Edd;Q9tM;QN#*I7FhyuY5IH>Q>O9NU0GJVx@dj9wb2v%zri@OaqVp&Hr1;=viYDR03>OKA%a$huiSUxpjxwOSXYvd}Uo4)FeujL?v-q(wBq?))_ zgx-E3SE8lZ)|}xO?1;66AZ{a$p)D|YrH>H&9`o=ppPv8qGBFfL8vdMw=?ZqdETEM@ z>>A{>&W2ZYS+f~;yxD+`yvIi}DU2$ZE|{kb9o**#TSRO=_OfA#Sf|l;I?Q2(Eaexg zn-WUKkUG$O_k*xNQTzQpak6MSh#t;hi9R(|){lQeX3U^$0dfL@qWuKlu%=%&ZkWWx zz(pOqp2$D;J)h~Mfhdf{S)ja!C`6P@B`Rh#g(P`L^2-7bUq;&95;@E=OGO@76n%YS z_%-SFq^#9BN^-uHL|YDNASwhstNukYF1yxfbUrbN5UNX2XQkcv{^Yb73JWWepDHjX z0JO8mQ`Et>%dX5hPWAlugiyAM`7lp4tab0FU@Tr>&5W85$E7D~UC}luMahp7Smne( z?J} zz4SNk{wqDEl|Xc6xUoRon`Bq@ccq!W)!H7da=d4_HA91#W^4BKrkPgM+WnIrO|!j$ z&Wv!7=7K>M#eH^9Y@fF6W;oQZ8&9S8m``?rSWUAZ1HZC*rj<<=;DV>3AE$OsCLCO9 z9Z?XiA+x8rT71hGV|*UE-LAAEs~`8VXvfQq| ze*(IDcG8CNV8*z(^=>any>DEPZi7bqhqs3hPNhx{nKgbhT^`jIPBaipk>5WIB+nV% zNyU#(K4UqmVT?pkw^mZ6hlI@kz>!EbT(q8|1ocjHO&4-GHlAG<>0TEYag0)utr0wi z*lb1^E~dSNf^f)F@u{@LiHw^D>m$>0b<7VSufz=E;kmA~qT`5)=%2UNF1^)Fg}rF{ zrWz*+GrBx}b5e9>#R$2i_`7X?;u=L7ZC#I#jN6)D-b^3`8ebwZ4--+*R?b7N=8PG9 z0Si|*eeg-Y_&x{-R{tkUuoT|<6fnX#)2M&rz#>e}WP4?(zz-{GPFtAk@82 z(E;t?w1QyVS65~X!4sT!r{W@168oq=L<~?I+i^?OI=J{17vS5g+P!?b?0cQWsTEOW zhSY(CYy9P%-piIRcIu(NFua-<{fzj7RZ=m)*i7%#9>Nu&x}HQQ7tT$drT66_`=lz! z!OJ$(*4tZFCpF7^&xb~OKFnqEFmslbIiMM)F>~nV7#ccK=>o zdT!x(`k0K~{8$UP@*3K#IsAyCI?mCy{Q|_PJrFy7&HSStHJR51_V)fuJ^KBJdgM|q z32wV@vkSH3uy`a-i!Xo&y{#m%W7Is_$g1VD7oXi(`Xs$lj{4qS1HqzdlM zS|u;Q90|x2W2q^9OS;yUFQ2HvmYF6|apD zj>EI(tAC|OHA||kztUqUdz))k!C&byD94~+X_S?-&e8hvS$P{uxF&0D`29+m`R!`* zn)qH&I`77kHvtNED-2_kyh>9Q%pqR$Rx+q}9Okn1=+7MJ`@{>+(i>u)9$PR+($Bnm z8ub9hIK9tC^GvpvVmZ0ZihGW=YJLEnZUp6d(CBTcV!vL#PjYcJ__bc2 zBngz#&^a_OWx>nw;`Xv!>tvbI;S{tTlrYHHhL6ftC;%O0Bhj(Gb4_x%#5TovT7xqo z40y}du9+evSPSFb9ZNEEaQ>wpvx@1+S60tO%0BHU^UZ+EV{~1^UIE+x6G)H}hN))+ zP+Yn4j)Ee9fJYR5qYm>;&Sg>R1PJ+HEPl4n>rU^7dA6ToW(zeYIIbnH7kLhEBX9E( zC#v9N77_Ei3I4hh*YQM2AqtOl#6c5ZyJpQOm&@?w=tk6RxrAHIP|*(f8okG~=nC4i z&eV}yNpH$zOz7!cV~C%f#HH#FUbX_48ng+a#^Ud^IRM-)6-IR<=H~*s0|yBKieG4` z%Ivh=C4QuF%)7+?jp~WELlYk3AF0C&kZED-25PsRSFooC=(AIVnR(LxT91|gtjF=U zgYoC&n7`H|MK4JExu!6r9+F71z6Ma%bec0p$J|0EQ#DM%bC_(?U+Yl~^0*Plz)#?0 z>4@oV(zHV*%36czsxQ4xTT-M0#gH?8boz=OXaaM3xg8@fCoSt3h5D%D{0h%8=M;(7`I+~ntAHb}twp^( zw>l*Iuk{$6{fb7rLZ>q%*OPmM@dMqFM-T|a6MSLd%9Kyq${SDtVy=6g^-X8XC4nss zJJ=VI#{Pj04F(+y3@!*15F^e83kGeGBm1GjgG`711HI9iOKUKs!gZPPUoi0j!oe<#Rp;m3LO z)F-A9K4rD;oylr+h_0l{h9vZ+G@@SS(o*lb_O$n%|D{VcWRv(4GT zhZSKgs_%66J2L8XUN@B4`oHk&19c4WL-L>-ZdN`Q%zLnz2j*Ivd>Jal^S+x3VtRfz z{3TVRh8z;;Y=jkV(sW#jc~T27jSb;w#zeDX6P%I7VfHC)LY^tvjujWT;FA% zpXD%iqRo*r7FI8OfK;);>9i$H!ZICweTsP#@_K+~vqNSpTf3*P2rR_u1XipQ%(-hM zuAlG*!FS;wI|y;hbz)4(-EC5(E*!7lv_B3hXO<5&yEVwYKG>4U3wGIRF#Y4EYJK4g zc@3#lmdAa?Pa6QxBe&TJgFeu{YNVVJWSxYsPwnax@MJTJQS;?D0Qs0wm6N)LL%{O0 z$<+Cn)k$928)p~j3R7))W>Rd!vZt) z#j1qC%&O_7zYw*9G$ALa$E4*(ijYcRqoNqmBY=547R;V@pDhubu?gpCYDLM|$;+-@ z=O8J!%;!a0Y^qmhc-$>m3%2PM+hnr9NklEh%8T1~soBM!7LSidK6}__mB4$i@1uR0 z>P2H=nAF1fRTw1tz0aCh>=GN#)-1YNX?F;9o^U4r7yD!jHI#+U>Wrf$+9IXOLG$<; z-STitjwP-{y`S>qkI*t2GoIk~rU|UBkA-l`6O6ymBQxN%Xw^UHah*2Z)K0-^b>r8< zf1yV$uIqo$qp^34$HX*YMm}dq{`F%|6{M8y9T5|3b(e5@bq`-iZ|`Tk6q65BX5^M^ zs00eN3Z$f!v?+~Z8z)|ZbDc={pL}C8YH1W_jeQPwBFp(JDE$`7rErMg`@p!};i9-j z%L@<1(vA%i*gyCCLpK$DOd5&flT!sMx*Iz};ShIADt-1D7#uGS>t20^Co*z}N1~T> z&5S$2`lmNBBw_mB#IQ;hP*_6*sA2@o+>}kjS>1X)wWVnt`63{XS!KR!r=a?VOFz+l zgET@Qe2BkOD{elrF+8VX3(t%1A=3z?P_{_wt~ygI_Q#?wx)D zHt9G2dX24xk!0&A^;&<*&Is=zJfP$l>3DH6hAd-4o#HA zE#%3W^QIaD=jm^-V;CO`%$(&5Ge^nU`!cyOh1KE*+vr2lx#-vCU1BpcNj&<>&S=<^Cpf!4P3~ zcd<#Kk7!TeP=8Xj6l=L$r>od=D7HusgBEPhP;v;@F`Vh=)EmoY%x%yp+14(sK(psg?x*UEB8;Uyig65c_j*a4-XXD9^_=!9Tw8v!H00RYcw!r2I1@&V8Hg@$7fh)8|m> z^&bhBgtG`iR}9hRO20Q_F}Dq-*MH6G7!`I+SS4L!Z|1esE3Lz0{A}uQN)l&) zNdZ~kH}4Ac(=wNbd?icNw01rTa-+*x7acJRFF^^1TxLSug=a>Rs@E7prVOy@;S8<6 z&f{tZb>+;bMh-TYZf28{f%P@A?qzh{;!>Y72!?s@V(059(25O2<3>HHDeTf{IYW61Idr^NiI}9Y-~nVsHBm>vymuV4)#@$xX&Sme;*VFF3RvvUYhF zv0KFLxR2rb*|$j+uXNM!Yo*)udnXu69JG=ZWM?sQlngS9_HmN0Ozsz zS*(wSUVozkFX}*_NkQ623lXOb=Ai&VeTFU4(VZ6~tIqLGD6}Or%9Csfi>-zfe_aIV z-W|;3jYMwcRYwngWe(%pDr(zMp6p<~dYw`hyz08kGU_)#-lz$an(G!AJ~^Wn`@?6O z^ol5zCUmwlV0cr0;{@NEgkttS1>zTwF;Yy=$^=!@;V)Aune0p+LW!f5#<5t%qQXC; z4D_m48k1pkoaF4pq^XQ^=X3M~6#@BOQT9B%?R7g8D)x~Yl)+GU)i^jfSqIOm*c-)u!JgkLyM3Iu zZinEeqqChm?eESiE0PkHwQae)p59kq8lqFOJKbOIRuig=b+R(?e!IIZ-7dYH&L&iU z%0y4)yzkWAa)3#<@HP`V=B?zY`U0QAD$r>^uj&$0WyZ@--`WthoA4m>naGzKK6<(g zrplc=QyJvt7FajdXiI68Q}&?1bxh&kALHf zXGWraUG$UE+q2?N*a$(7RM`?2;cVG>4o!R+AfPGvCLPrmvo*c#`sUc)eKzv!)UbWUcbh z$6n&_hI_)s$3LC0NiN zHT;_D@*%UxKH5Mtv-myUyEY88E+Vc=mHGvcDP|h&F{CG(LEtVa^n7?o%y^8#Z>JkM ziCvP!22Gp^j*&6p z`JgL_ztrW)!4Tdc#kar&-JJ~vN><_gI9!$_*RuE?bms0Un3u_YL>m8w`f&*t&pjaM z){4Q~=1K-9a6t5DI+%6scxzS|uf>wJHH?|(=%4d=^{6bi6vtyCng|Lk(9gj$yw))qoL!8f0%A}|UUx??g&-bc`$ZRb>f zD|?Bc75m6po5-8YZLjKD1bV$`%#D|Wrjyu< z8x{~bZuZDWeVhcYkvb(T^viU`D&Q9;O~nDltRN~f>2onOgj4Cx;7qKPboUp!>ftQ) zT@V4ROshjr>!^jyR@>xSSR7h8`xy>;ypYjfM8?mgwB4Gvs?sgt!Eb>ysfw;mcAGqc z*l=h%gd>P_o)xy2hi{GPCEFLa0{C(1;}R|GSD?JYfs~3=3LptYQsGpPsYD%V6K2Sp z=oz&eg8OdVLqJIipx753cK+%igs3*470~hgSoc!lkV>1%oXl0zzYPGZ>)zA71exG) z5$)Mj!aqxD%YS0#g@od0e6;6p;)fpQagz=T&)b)>IwcOaFl$ z6@*l&h#Ih%zw))Ki_P1vJ!&zn#Kt6g?u=WNfxCZYUyhmxu|uAmSk^LfheIZ}D}Gh( zbBGwG(4#6@^wqU~BM>s|xGy(p5~=Bkp~ejjW9X3}+1I4KQq=e@nSnhV4c&8ee&MJ6 z7kaF{y8iqOCS@Oyod?ANiyPOQRFQ7MuC*}}MRXT-3;YyY$zzK5AAydJQkdtA4?Q<2 zs0H&Kn+@NCXNwr5n)SH?zGCRn=TxW}BhTm%m!=1HCy$zR{est$=cL5K5?x^KNZGz) z0|h{j967m!VJHpbRy@Z*5b#tz(-u#G#bl5f8X(K8iT)aN3=B<|BJ6FBuS##ALl)w$ zmA%!~Xl4zRHgX$)EbF+){hwH`dUYc9hH&m1uHZVfHfu{~Vv=p?dcdako-$?<1R_7} zC)L7q#3>&y8?iEw3}XhfG`n?FFOY$RmLb5dOJAsF|K=k(L&*V2%*K z`mMMZ(T5Z?JC>SykLok8TmEZfo3uoPy=Puzf=II3elR4y4Zg~I3K*wEW}H_bX(pY$ z$IN{04APU4qc4Emz*fZY&crc3bR2ZnXaP<_s0)MJI0X_$J#@xq#a6Q5t4?9L35}}F zh_^mt*aCaX^|r>;TtLy;?cTLa=iX8!>(?F>!WO$tEwA(@Ct6w#ksMlgaO-GvFH9_`?OPgy;uip$TlwK}oS;;a;s z+QjMgR;`$W&P-<;CFMvh+-78#n+h8Qq#{#<_xGEz2IEhf(VU^8S^Mt_N+tPwZ_$2B z+Orl)uqLMaE&HySJXUam>UXKM4TpsGJH6r(hHX|giQk#)Sx0$R461wNiSKBU+O_5q zAp%3FWa^S58<-IW!FZTZQ99^26(WqUC*9*i>7WwBsV^=W?26i|5Nj%YR_Ig`a1laC zaQaeRq0>cFE2(s~^*C$w1TR*o>(L{wzJIOj}zidArNq1=6TL1WFtchc&|Y zEB3ZQ`cd7Z8f5)a*g{Z9I+@pXzNcHz9ggvSnR_{=_1JEN$a4>$;&^j?A;0mMNA>yG!x#(ipL{%ts%EH?QA*6{MI(hx@U_~r;5#$YeJQ4 zr!8f|C2eNEzcvSq>9T)p5BHP8oFp4_{l{ZubMu;oMHP#{_LQG-J z#Hi;Oo9K?%L)7(b31tn&(9PBL`cs_+YB2upPls{)@8`*@ZAMJL%P(T>`s?JVEqhO` zs#3y2Iy9sX-U7Nm#?QxLpEb0TvL4$P-D%CAUe}V$QlbOzdxdbH93O|{UACFOFRl63 z{vdx<>j-P;EOA(mW4Q)5cjB*0e{ZP~*}@@hJE;5R!qPe0P?)FsZgxKLIuvA(c9Go7t7AEF1?O5%cccz9<90#Jc*Ve|KEA!BRYxsQS_MZ{?B<77#Q+= zBg(H|{O3FpGBEUUnw)k&5y{*wX;S)S0-VPpHqEzeFfNbRv%%S0$#0aL>>OYEmDK&O zrbUHiIhyo$^dGOHfXC9{(UgX&wd)Oa}-n)Iyn z)KoFbV;!sx34vx4c{+=^)Ho8c=7V=e_lIl~r6%vwvixsVLi%Ds^yJ5V10%tZ=-R~=#Z)(U-RH2XcAf5?Fd6jjch`Rdzz$v>7aPe6)@)m1w=F1aR(_;#U6H5Yh3RegOg?_g} zc^w*0OKq=ybLLEq^DL%2M|dhXOr4p4c1cuZY`I3lECIJsM_gOua+Pr9!*`c}M-339 zsv*#i4$KXUw-{ypjloL$ff;kDInK>BmX3AWkRZF@X23#U?li+=qY&9HZf-xSz)n0| z#scPlO`=X*StUgbJ(!yy#5x$>I^?av(cJNLFFO>Z^$L55$Px+-UK0YdBS(T*tG%nlM^O^5ub#U^6SXdG@T(Zw>lsz$&;ziAM7J~^F3eo#%uW=hRu#Cg+mhVcVIQMK8)!5W_?q%0 zzODzP)}1DX*5h)SHSm*Nu$9n5n|3iL*g>NULNYG~jEHtTfOlQGi#-?}nz96WZH_xo zn%&@SaMmY5?YjVf zbQPB!i|casyUd#qb0|V9^DYH<@Cak*LNHBFv}sqQo4lF;XLC^~Eo4&DU+0l%7d|J| z9&ke^sNd$|m($NSfb*C_N9-4%L<#bG0(D{4Xi~5A*LfrcUZX93BEmw7iw%k`d;RM? zQpB(R&w0GGaaW9-#Qy6%61rG_HX^EaNY#cy;$1o046Y^fn{}i??7yJe9J55RqVlx zwq{ej-%rPGfrv)JFC&MwIh=3Zs3WwQkZH+r+g`(qJ0{t|dsew^{n>G`8BUB%WYMU~ zqrb-PvpGM^uFpY(&{QJ(*4cEsgCKML%y2A?-9qMD`3-cNZ`5G!*VB=FlwNruV$q58 zt{F9U4so`Pb@%YCMmKNDMT*91kSC>wC-qGhQQWn&3F9PMx%A zxX0~ldDs%QWBot!c!yc>J`tiXI2o%fM}ZxOhrcN;3Q+vZ3HkD?F2zU7bl$=rftTK! zny$I13Pg@A!dpu5sxgG+-N{k)y# zJ^JZQA_;3%_J_pPaO8Xco{D_(jM&%wC}2YfRoG{sTm6q}ve@zQsL|c<^w%GDSDZhG z-m!si3`M`h66}7@dOTNfv(f;bIeT}(lvzC9FGB5Ko9~1Is+r`M7A9>eV8 zX>(T#bDVVKd(j0iepY)S)a7Kpp3DV~J$yGDt_zaaoZy5*Mxldo^-*9E7Cf@g#39bd z?@o|!g|VLfNh0hikW@Maa!q-j+k#!)7Z)Yk-(_WZEZ8iOnxEH^F&U#Zz&lH%q6!yj z%~LpQ!GE2$>t9u4_TJo9<+$<;qaAWWcqtDaA`1Ryqg}}#za)eHi zVr+3YvgiTci7hh&17(g|t(KViPNY)J)6xEY`OP#aXT3VO=w*e^HO)f}kRPd6u{k}q zQm|7jL8{n{h{~e4jYe~ut+SxaTeSXhAEXa0$!p%^^4n( zO{xi&ECbc^uzXB3nfyK(l8JiUdY+DnhjR4BJrLP0ov{Jgq0jIJyN!n+K}T+XayE45 zl|d)-S>E`ikb9FZogh3Nhl0-@VrtFYb(tWs*5#~mZbH}Q$3thBIl(geu*Nx!Rxr(A z65>8fS^J4@UjXHN8r>SSt{5z>(^aDt_H{I?Y-tvYLb_?Q(P$`Dnil#c%CJeT31Xa| zF-oRC;2&EB0j@_p$n1|lSsOMariP9%_cE-xt%e3%SanCfhG>>FkVP&1M1b_>#GpG& z)~`Z;&vRdD6t%pu@5ojfwZrx3cQ@5)eaF~fSvYBX23b$k#FXgAI4PwKC#7gf+?kZg zRBq{ggZYk%w1YQk74GH(cABm)XId=_L(Oc}U|sfU_^6;V*hZ*k(!+6SU62Z?B4+#k zE+~{F7ZRP!t30V}SK$l^yusI&vQ{*tXM+9MfP~=D&6+2P2TKr9P=SSTcuu1rWj6g1 zRbmAuK67d{GA~m#tz(eY&_bSrhz}gvL+`BX&5hkI=?rQ4Z31C@wX@&MC8=poqlVn^ z)h`-VZAaXHB8s?j(NegpY$J{vquxK5;L+fCCKnOJz5VPknC(7DK}rXO%C6_b$$gWE z2n-uY-R*+rZ3z*dB+j+(Di7vs0&oV}`6Le*ia8e)=(rqS!IdE-Flyu-#!`I-^RHwU z0&H2ZY0ND~s3Cv=Fb)qI5KHKUiDb5fqHjLz)lOItjeuB@MCevsLWljZB^Xa7h2oZJ~i)cMrh9}VQf_+s0%Tt!dk%3gXd>*#2WEitj z1~iqjd`EfLDppf}BP_?siB@EBDbvsHWT+V>!{)M%B`8HvR@H=W;BXMf-z}>s^=~5b z;nAlR_*K-i=z)jwkd`4cKS;(n@s{nuF%eACesff{;52DQzVGCPTgmAZuMw9s_x99R zfjll?Dqoymw@LHSq388pMS_cw-sU0?YJLZ`VL5t1zw3;2bwQ9>H&3;MDtOe!b*Lu0 zTN)aSFCfzny|9-r6VHo=s*+)5xweuUhEcU^Jaq+@+c&$~?nPf43XZ}>BahP^6Sdj@ z7UdJJN?LV6-o+}W_6qPfH=QqMgonsyS}3aopU=-94j|1=sjt<1$C6#9avXo(y;q(m zEz4?Z-a^`*XZhBf$k`sFo<+((Zi;dnD6*2~u!wGN=?CB>TDP19OjLhFAo4f)m_da< zHr_20EjAx&vzTfX8{lxCYXL+eG`NIf5{pR++9f4GDCgZP5XUx^x5l{7ygGJ0>W#mcV+CQT%IefF@`kh%k$2kn;m}c1) zI`F6FZ85Q0)_R)fbFWn<+cbrX$rJMs37E(Ue=kQj(A)HeDV%)Q!vFentleQ0rHX`| z#g^Y&_EK}PaIxR;@Swyoc^*S*;|A)KdY!f@W;XcF$+nhh0s+WOWrl@qJqW02Ue3Wr zH}}r6u&se3P3!GpU|R+t#jcQ+h1kr4RBo9vt4v!C&?I7piTKEr`%eIbbK}fK)vjR_9)Xn6%T`ifqN|%;hmFgX>FE5KlG!HGfH9qspl&Io2rTR7xSMTXC{b%Zk70+$I2OP)hTRKMJ#-I&!aeE;`uZQ%kgsxbcX$=AAWt6Q@{WLI z_1amr>&(+NhNK0k7B&A@i+f9Z-wdcaz=lwFuPD0Os)z9??$j(Q%R39CRp?Tq8mLMS zw?IyR;|p6sMxa@*L&l=MP0C}&ML9FFTTrH!wNZ=>by;xvCF1nHKvfP);54>tfu%C8 z7fS2t^|7k!`I@Q3-A*I@Cy3n)l>nGEq|D1)7T<8&`tp^!0|Twk#FVuNq%Omx$`}eV z+h+^vMODuDQ6u}q?qR=Sw5tX;9xMr}KBBug1n&F7vMsGiLV$v`-eE@_lv{!d9Y1hm zIR!Pc73Jy*SGjmK785$UWk;s`D2NlmgDTo@<{XP)rN*z__jk~BDsxU|MrvQusxm&n zhDvy=5pN^*YZi$CCUYX>)gOfqePuT3ju3hz0)wV2t?!N1UyaI29@(;w?+bkxJ{{HM z>$8JMUyt){yCi}OaD(F$Ls#(pLT*Uv9HI8d%Q4Z?UoGb?cbr>F=fwq1kGJPU8t3cE zED^499-0q-H15U$``;%ponBDe3ZsCh32<@RD!xNI!>mCQ@j+t-Z@EBjyc~*o#IWh- zt5v<~Q$>8&w@)#;kKekpoXaJ_pDvZx!AYJ zjFZintT>sUmD_lY%@sPeH|H8Mk~zx@H(R4tuKa4w+^xc&^~s88mf-YK^L0fX5POLa zqvAI73l+>EXH7XJlX~f#u`x$W?ZXSC5nj@W6)vsdVTt=;FYP8_Vnu@}Li2)h;8!(r zWQNd$*psz+&*&oYN0#pMjEgx#tc85)v8@OZv2hDxe5jhRalTZahn*nw%&K2+0b#`w z{Dn&F{{XK*P`{u?3ORcn1rt2)n>>~*$P#w;maqQG5TQ1r&QR>vu_oh~$*BbUqcy<^CdFM*GP;`1;|) zd!Osd7?XR`LpVv7#%+@zt>DVN6~Htn5Z$Xqwjxg_YdGp zZ^uF-N1o@+IH9>EuLJa@eGXtQ=sHu5=VX~hDPKj*=59l^A2dxfA`-`jpBG{>-k85= zTkl_5y$gebW4&<<4vv3q2S=Ml(!J%?{MnH@y{^tY4EkH9UL8Mu;utF7pW8K2s@6{w z`9A^yf9tFIajQY5@#Bz7I*XXvk*6%=3F-?cG+o@esq^DIb-9$;nnvqLT#77R*Xoz( zrC9fS2#)&z3n*I*jechg8X9vHnLH}WW;NtlMo>a}K_y`^W_IL?E#lau31?SK538X^ z9z(hC_Tuc_%12u!L22@_P8iT`QC$y{x`;Lo8c@sWNcGG-it>3JX&z<$E7QQ?x~3fb zMb8P5UfS!r=_vqFpwi>aIE=UF@+aio#Hs(Zq^pT$>{KjyP|Mk}8nIbRmNR@)A7%Qx zu7iqr@mMI9lsAmQi!6{R`zKzLV!;&i{7!?bcb}C&x#5c8iniZGNw2c;~(2CeQP_&0oB#d2cGA+YHny zr`HPs*%n$}L%Cd?+jDesEQf4v`wZFKLpJxPmd$#y^qJV(^v-w-6wl=w%X#C4f&;0P0J84{X>9LyaxeZ4RNId+a3Z&0#G z@uw{xkq@fcj2{-DZNat9foS3 z-L5w{7R(lTAZ86sCuGT_1T{O%pay)ZSjjSW-9)oU(Sb$tDUG7tcVql-_KwR`{wiX& zdow2QreLXg{FvOpf9;i10qKgLM6~7_QD!FfmUBAuU}1kX+ai;7;XCcD)XYe2Y^1ua zXCe<4YGt6dxSU$%X<;3@;%Bh0MNPDVmtZoVYxy9}{N-KCqgvG~f6gsBqB@`RptCsC zfrVgRi9?!%B%(7G=?-9KOB$yv7~9R02v0q_vJYF{MkFD2*~=)SXrL( zC#Zw~_N^kRkgz?X9L@@Z4}n}5=IOPJtM%Sg3aW&VP-5Ja3(9!srB zjtRviXb9(vm1dt%^KxUSP@G8X(Qnxed|a=Yn#U)T;B8Z0Sq(*0uR6*P=dXUS6=>{~ z>1q}6T0xsXRsF8;SD$17LpAT=cccf{RVcV#-m;q=SttxuxIwiq06u>O_+!&Na_Dh9 zCND**{^uDSGq9Xb1(PpD3cuW%J~*^ZQAZ=na0CZZXEbE&IJXBmCC7NISW0rKv~rQ? zskU>(f|*XRdE*m_MLYq~RolL%o=6JBTeB)C29t$56HVD=t-mCH zmMpnsWTgaN+gi2?Bt2fg+?jTVE%AaBc*~l;omjHBYLjci3h2Y+xe_aPj>go;`p%e8 ztS>2`V*f))Z{VPRk`?8NoRT9j{6wtqH;q*5G}G7-Kx3=rxuOxn{23Y(hCt4$&+^GR zCf5rg@hGtR!sso#8I4;UkM7nP9mgX)gDM-s9#|rdZpaA!Hk$T6Y}bup>F1`TE57b^ zwf>@d=Q?4NG6=ZJ7WE!74ITB(WDPjuR!q8Du{dP5svPi*l3Vqicwd2AF28qq?Hw+> z)sZz^c(-@eWmhb@5ph?9*)#nb;c*DVG8ICjNLO`)Ew-RnEVoYAk=SaNENo!oHoqwt z|GOjvV2tOHSb>OTwq%L^*bxYql*i2oShnu4J{od=jh9lM}Z=OX@&M`>L^f44Av zRcykduggMUn(auP3@CEc`H@@uYsJ{{9P*SP(Mhen(+ZTzxS~9wvwCBey|IfRkjk`*D83(`k*}5j9)Ig zaCv@$mr6Xulop}gJCHA_h5D-20@a?yzm{|~T0SK!A$iKL3@$^foFspFOo|k2q>kUH zoDpf^qPCC`sjwrKS(?!(x*_ac5M`2Il@A^q-p=lV%3T!T`tv>V#TUf>itX?1k#ERn z#rMb;UsPu8d@_~%H@3S+{z4A+2*xYyIPc#kY^1kOVo@6=Qp_=>a-nn2)qhpoSPgxW zA>73K=@jz&wDBJ%J?hpB&ck+DP_J8EJ4OstAA{{GrF z>n#7!ZPo6-!ba}W>R-qyIXXEe@WW8Acd+^oR{!6*)xVm-)vV;X4Y%uhPxF5`Na|hj zI<=bE-!oBHy|4r!EmB$#B=FUmb%7$j7EB~3b(aM56|Dp2PHUUX_)!mU{8;kwQvLju;*#47I^`lp3(Ek>nV z({0AmYsO-7i00rw{pnACT6mGpjC*(IQ0_oj75wGT?q8s_ooY?Uw$w-9%|4c!gr@9y zJwq3k>(sng*hcDW>~q*l!(Q6xUOL>|MmpU3E=qaYiHLfx-Z5*m$d)voB#ef17Ug9P z);Iy{=P|({-GLpbkAkonD^Pt>`CtS3grA=FACaUq+I0Nq*AKof+kYMm_+NMPeB|~Y z&2O8q06|kVHX!)D)(V83*VutfQ+H|!f=(SL99(jhyeBvwP&l*$PK)eN1liJ8*tjWF6fdi;9yu4HTEgCB&mO29RVjW#Q|jE|8`; z4E^Tm^E{U{OCpo_s(!&Y$m|BofE{IN-975w^Z@E1s*H zVb3q+@C8w%tC>vI&CccP)91VID#^(i?^vVP$4+&N*T*CPWyO#gQoR_O|{uZ`qp}Hynp6geHXXTUQ%X5_t5@Z-J`Z2R6^lS6~6++d5wC- z-mQdWWmSTp4y5(9pV;hm?`ZM%A|=Igp!n+3!ocm1ea7rH?hY!$;Kg!90u^@Z!+YcgnBHC{QJf~aWe=~@+X3$pu zvRIr0UMvtEzXifyvJ{R>7!XbIUelOnqJ#AT52Ub5%q?24+(y<2tK+=%!!$j!FW0S( zF0_*`O-nGhb1dqjON|V=nQ3anw;{dHWJ{mqq0>2Y7ApSrRG?JNe&i0V2Fm=ObJ1Q{?R2F!@+oCeH@#_F(`+roSy%%5!Fdm^NkwfV_!=MIzAL zYvu>?jL+e`PRThs8psdXjPO{dRGs0qLNf)yFk@rFIK-xmA`#GNq%KsWkW1~&4M)|l zS)A2)QYQo&sQKM#&7T39LI|sActdf7TgFNDw!UsARI;I4GUV+I&mVgG|NCP<{h`zU zfA8?Cuf8hz{|^tp`g-vH-^KHB`~NrM_J@BJy!~}f{u1BW&`QRP&r9>p?EGFz=gqHcX={7#4JFkU6%iib>sN|R&( zEMO^2PF-~hNrhALDh`;|f>N%o%wv5~H11(_K1nG8_@mP&Ts~<`j^oRONjWzEaVoNu zjg^L^<_-U{e&;b^F`Y$)h`lVab`1k)12KHYa3iu*@{o~hkwoDT;$WX4#9;_=_|!ri zj!urxRxBtXS5?fJ%}O;0;}t)vbW`c-6^d=$UB0Q6WC6m_ASD#!vwqbG+@QgT)^5rb zZlOUBSAVfEp*upUeh_oF9AhfTtjT9#&Cnsnjwdu$Cm@+aJw}lFv0LeOi;jPHPUMnb zf#U#dsIF7kTH+1e+loY*=iD*zJA?td-Gaqn`r8O0{Ne&IG$ir&AHUEaI35)f) z^cQKw2MJdcrG>$?woBZ7W=Go|7_j8Agz&dF`{FVvi`||58ep%M-UHNUtmAuUI_=T>&S%iSj;GsAMx)X0oBcP_ zH`6!!d++ss{@dPYG}`NGRPn+|!sh(l8r+2+mUs-fYXyJt;Vw7EW?(Y?{0^DylwGoQ zcnrRCSd5Z{fk{H$c6D@$$DCF)Ra!yuxOcd2MkNc00PTk-Fyf9lJJN@vI-`}$vmV^jKcD6OzGAtoo&qC+)nmiBXM>EXN*5{!5+Z&U@zi~L_Utv^xzf4i7+JXLVcj38{@hsmb;$X#J_k_3&2G`03)rH>8F5ad&r! zpV90aUucMbAwIk2cIDp*5mzipxK~yDSNc_rsiJQ1B-7?b(~R%Umv|}I2!zwJ^E(w- zUnM?k0(8lr9%tveCuciYPN!TzA%ti-O1!ikm0fI$!^x7WV>y4kM7o~{@)1B?;-`H| z6T?j{o1}3n&36w!Lq^?2#Fzm=TU5G{4ruw&vJRLMdBDi^g6T-5+U=!73W%5~EvG3q z6jL`$lYh@x!WkGrLzc2+34xFrsw%h6_p-$+L2$j`!NQuwxFj@9X|QM>)N#5a310$Y zA%@|`B4sAa!KUP>rg#i6E-6$K<9Jl)VW|PRBXo#uqoHOrc+27t_<%RWXBaZUg4sQo z*D$-{lu+{hvvXsr)pvE!F|55U-$yT=t8x9;*{heJ7DVta0)b-!)GF-i-OY(_Et*?W|xE%<;yNyU20?|IEr(gV+kyHJ` zz`EkUzW(ZA8UOvOuMdX!ue*3Y?)WduZyN{$(^G^W3(;Wu4|PFdg;1$NY}l1;tvf`_ zO|68uoF^j6mWDbL@;51Bbp?4urfOnSw}1$e;@tVABBH7dBrIZ77MnON{8njXbI3I1 zNGNKkq2rtiN5Bw;HAGSwl=#xw|1IYlz7jVzP#q ztRW`rBVfrPCTm+US=x!Z4&s>hwHn3R_&*&?yJiqhFp8sV4CaNf^zg+QTmBVGt3l+8 z@hVBSykf~zB$xY@_8f`TjGVa*WH`e$I5=|UIN$4*rXoWA@6|WE2k(DAoc!sRH{q9i zZ>G)v+WqFyWOw(QNBK|h--KWOOeen`P5x){%g+asKbilAm)}f%U*7w2Z|@uR#eeL& zfA|k*r0@&8`EN?bm8Q7a8pn-caJ>=UiXj4SBb$yc>*)>LOpsZBLjB%i&ES`8W?lM^ z$UpvB6M)tf|D}K5cjCV|YIlj!?lxHe>%qf&4-d=rzwX^1>VMtI^O41WJ)9oe_^%?r zHAjE7M}E0?68Jff{c`_QiT*0|j=Ramf4P6VOOUX_{Ysw~Pfnkz%Nruu=aEdgK74+D zLg0&J2)nY+5Oy_$U43d{SMKhwgg}{iECe$a^TOM{x)+Pn3Z9 z&^$qo067gYP>Mh6>lHoA-o0 z!q3sy<(;ncPrIw;8bqAnP_H@o&4c)R8e^mJ_nZ-YQ<)b2TA5qNglZUe19R(kPPRJD zy*!g$-o#bHMZ(j@0*bx@;6%4mF9S_4+mnN)hgLE)l`bLL(!+z>OG52=tQUj&kIiJz z#VoX|0*abqNiBPi(^pR8;G}W55A_}k(x&QMZR)a*lrw!gsM*;{rU|1PZlhA+e1S90AB^_tGr|h{6^qM1m%9FA-`X??LvII z+^v14M8F&xMdJFDg*;(FQ({Ep^g1eG;`3dx3rmOV1%o;&iT#VV4a}GxR$fU`akoo1 z63{5}2&i)udTU8-d)kUtm7fKpVMmGqK7GnDRtMu5Us`6n&`o9tz}9C*+?uZ9K2n!g ztWe(=1AHSIJpvU8SqPbSs}$9_>d%T6D=>_Rxoy;Aw)+05+S8OW2Y6xb+SswdU`~QY zt}EIZHAR%Del_=r8SXxc>fT?6*}R0nv7TXJmF7UpIJl`LbpI`W|DZiLhm<{`JWeMf znc%FwL+FHL$8?X)n~zu=f=OUq|0Tp z3dUHoE0Y+Qb$NR7q}cQ-5vd47q!0ZW)2VpLm1_%cek_kDwQrM@UN@1Zm{F*v0U;?6 z3o&o399$UWZKbl`{6tdYMQxv-NYcjnslVOP{QQI;xE=a#7I5t_Q}DVnOKj6)j;0*o z_Sdn_^WQy9i~w-glD%88AZ4Le#o+~yi3Un=*!!?tiCD5))uQL|>bJ%zUow$-@bRa5 zyq@C(3oB*HZ<=C^){O|F_L}k(D+1NhpUl`?-IW6oOCB<-gli_xV*IG(s+~Vp_I|bH zOqW7ZuGVC)dXgXq%^-S<~ny_ z(>OA@Tjn#p7KGbMX+mq9KvMIk}&%fO)&tRJ-x&$irvzP=4qt>Y% z2^vmjG@^09lCHEaV_SeyyWj3e5-fNWCM<@8HMBQG7@ofpp(MvA5cICY;K5-8UlP;^`zLt(ygiI-P z8(wkS>IYeKH7S{gmZ;Uwr0LYm7{_A{Juo=ltiY*gM&GqO$56suTuW=V(_Zg{(O^Mm z5yL*r!JK5VwDtd@n>_f!VIR$QWR|6Fo(ohdk6C&xlD9^9z$|;QP`)agWug_8@&_SP zv`cN0kxmLNS8R(;u!?Kf;b3>Yrb&obQ1zO%G5cG!>u6Y?cO!6lC(E?FSrP{I#J zcZ2~l8;Pg|$n}Cp>O!=-F(-wk^h|_aH=!dEvr9x0(rF=#B18prN%(TfLQYc_-4Hrg zVqP5-WNv zzyB{!>xRsNh5bk!@@g)KdW>WaOJsIv(Ccz}cyO@nzF%${VZq0G)Q^F+X{lg8!=F+C z22x`)GB@?xpI^tRIlq7x!84BhQ6n%wQgcZjJh(rGSBX$Z?KSsP7CK3<6N}Fi8q4kj zuP1FwZP#8@D=)bjxmnjNU9B$_d3+;YNNt-&)EN0rf{NH@tQJY2pb^c zHO@}oB}sYkwlQ`CpPmZ=Ef$#^f078nBD+Hn-Dl0X4x^Uue~!IROz#^y=>j3%^1im^ zC-6}nZLqn1l<6~E^(gYaildIzt{wOf=jSKt(|Ro&#_rW9vC15xk3c3po(>Zz|9y0F zEXR1VP#@#7dj5-E(K8sU&#BTc5`bWK=Fz3cQj@hb8Un$est3a3kOwq1Ld)i%YDI=* zampiyc3VR4Y$tkf@oh-1W|^lW;UPuUbC^4Z=t1fF+XkFOq`CNyQ28&)!~&0>tCpdmq% zqPotQehYpBPaW)3WN~;ZW;|}lG{8F^#hj_7Sa#mqJQ?_!@yo?V72}_v#R8$Q6BqZw zuxjp4fja^SMYpg_Ie647`fHa$?vQGKm9T(IHYOt0&^2s1W1(sp$H_vZJptl(@VDR5 z@G%5Q%bPf*jhKesk-^YPbCQVeX1lo}*hecJ)-2xhmRAx$Ne&EG^Ox3zXr z_wERiQa6$?xCW)+oqZZC+5YFwEGBkjwcT{^cPN&WH-Yx}k^Lz)Q5*cPn@7P3p&rIW zkP5=3%nA$Ac*xzBC-pFDTlWXE$BF73MXKk9%mu(%XGbq@i4)Ij&^#Ij^FsAqjIdEZ z%Ti&243oTFzj4Qt2e-tf_f%ZEF;6>>(GCF4RSO`N z-`;wKO%xB%qEG4k`5C@7#$8qhtWM~Xsa;?MpgsiRb|m@ZIf;eQ!9u(dUue7RMc${< zHPv?BsEA7=JVqv(fVFLRZ>aWbwZBU08$@J@(#F2qN$gA`iL~m_2wV4rN90gHqV))lmJEpEdFS(qQEe0oacJ zcmLq<;Gm5E_w~I2|L;zoPXzxD_-zvqfagz6;4k$kfagz6T7dx7FiO;W+ zoAEN2Hwp4-WtQ6Hv;mQ>?)g{{={ls+#xUtxf#=jY(S=a91{9oXwhj%>>8?GG31H$j z2nM$$3DfB#FwbTax<9;(*;3xZkgGoAs@FY3u6p$ua@F-SBw5!!A3Dhzj_?zW0=H2F z0k`1-xlT@B{h$BNk>~Cs{E^`mSVA7*iuhfL^qoMab9Y>WKgAH#A90v02w{c)Cp}#t#ya)h(z-or)b%+NOBeM1br++(}Elx9CS6=fP_F*+u(_GRtR&M z8VJFq&KE=ycP2YMWvhg#l?xwL83aO>w0j~?Rf?nF8W!&WoY1)(>ig!RsF zYEEDR5e5^oSznzdJng+QlGGNxUQY;aJ@;q=s@FEHWxu=Bq;-w>?a4`>NDdO7=n=hP z33)*F^C*HXB`4Jodq_{JdxrF+Aw9``hV-N%J*o5z=}C8zp0qiqaJS!d3vu_GbkO)a zfInEu&WcKzE)tPlHiVXx>Mz*0D;OTId$d-H$CJ4>H`YJ&+(BJepCRq2c6dYD(IATK z^U;fFKBS@VgGe9(Y;N-@U+^04KvBl4$aM9zhSkNvn_l(gBTXc(R(Y|d-a0J^UVN9JS4 zsz}3-tnkNNCUsjF;d0=7fJ|V58`A~O&s4{pvAJ6Dd0t+Z*WMd$D@17+;#{ic<90LO zs)43{bS03%3N+-VR$!vjuoQju^kIW#NuqWb&`95oHI-OMUY|a1jQmWEgynG%Wudy0 zMLH8pMpQ1y?tVkwm4^YmRRtIy$Q8+HfV zJWCf!LPF9VkYz)$!7Y^e9ESs=>Cc$z_D7@TZHRQL8nDT_m|dD;0;xUDF%1W^a!u(g znxvqGgX0U#9g=|=MSrhUB2ZD~Sl5Q;YB#5nD4ugj4KG67;3jHYpO&HTdW2evE7n%m z-XD*Mx7-DG#`c9N;Z?B^HT>mAqY z9n-7dZy32!VJMH)yw$EFLBc}C9dxZ=-Zp8S&F3tst$Xhwt+Gb zsGC%I%|)`LDcD>eK4{rv%{EzBOB~VW7PHh|>uTD<|G1*&u4Y_4J(g6rv(}p8 z5>CNKSX|Dp4i3of@&C`>+cw8-WBY@7olk)p-?~w5snso8c4l(xR;?n(W8JZxUbT|U zzS#+yM0cY^5*&b(+}Z4R{};{yNRZ73upcCOrdc%;xk-Y+0dR00f5&R@sA7^Ir4+K9 z%f9UT$DUIb?{$A}HdmR^Y$ch}%+#4IoXCe24_1{8XR{@cA0gOB$km;tAYfA@dIUnY zq8JwBJfB?r`So{i$jSLfepqVmbB8pvw*@`T%KHKds?W*wkDpVC#qW0$<0?(n5_dAW z)~9&L(OlB5Zh}235=$P?hy)^@8|Vy8yhWY_m;wo+uRa%PCZr;lpWc#_|NPHy;TZVo zhMfHIM=Ouo!LhKdc;1!8>z&Nx4 zbK*IsK0kh^7k{V3_AU;_Wsvji2g&GNlZBu{;j7BSF8jh8WNz;CsDeGQJ4L(Yy})t_cSU(KvWLqMt;w*`)y3ca`sJn;h{@TAQXisL}fGy z=WBEcw49S$M9{DyVuT|o@Zy{@9Yt6+$(KtejTk0*nzrsL7{^v7tOboCt?Iuu>*-l6 zig&e6SppRhY+BVW#ZNQgEwr)A0A$k#$_uYZCfCMSAXy-^B6R|CEw#kn_wq2GSwAaU z-_$y_KU!;n*Cj4hLdP*b@Qp-*Q1jq`ZvVxn2DNT7cz;1dUs zMY1fHi6&{pNmU69FZ>-c}2`0-n0roeV zrjc<o`#rsI$l zjd`+P(_BM)RpT{J(0Cn-JOQGEc@9)yV~_*yM4YRvnqO#GZ@-E7eDd;Q?}t&ba<)5< zir1?q9#}e%i?PeG#6EM3yE4We)4G%_(1PQN-g6;Io@6{CG$RqCDywj5krWU)!HOnJ zOyZ;#MAtp+wyVd;HDNa&3FK5EDC{_sEN4?ndJ8@EPXC!N>!Z&w6EC`+t?YXD1h0* z;(^mDtBEV2sF3CrGn!;(yI3rx%7So~TgWmCTy0R1jccAJYmzIvWJP!Ahl1Oc@S!8bH0>w`4^H;?&Y zQVO{phJ=1|s?P*Rc!6XTY;@O{pIj!IyO<_Z{UM%^h_l?%waDwFK_JZR3m0=jYN-W| z-S@Y*Q!*><9S7mhFl^n?!HV`jb0%AAX819k|64au5vhN^`B231;CuiHPgVlrgy(B} za78_W@60A9sSDG!ZWy zNV^T$>m>#yaOoNu4|R+=E9iw8dgGV+-FquWqih8}2~XUN_wWX|B??+$E5=s=%jrjx zz5S^xla%xVdia87EQCHsZy08`52=pPo9Xd8L{K2a2Cq6b+IdG<39Z>b7d;p~_f|9J3c(6YGoo*MKRwww_gY z78XFSBv>~RbJ*5=HR;CF*#VUxX4$IEXWdARkMKfes4ItAV|#m9Byp=Vsj*|d)AUh` z0Gs_bGoruN3o){=Q1zM{EM*#;;<22YqFT$F=~cDaqS9X`^xtz<1irTGpY|%|UmwT& zplC{)j2Z4#!!*yT1@VoJsHHhb_%b40&oH*;nEm4!R&s9xPQ)FLzIWj9^fM{clm`q6 z62l?0Hlo4isIWafE{_A?aPx#R_>f_t(C*F^`<$ZP0<hKzWZi27Z-HhXb*SdzC`0SQe0tV27)C(IP}J?IJ5?>Xqs)ioSauuzAE ztc|B@vD|{)9pdJbjN^i}5pWOz_8JXh<@#*3vfT09in+AO~=LA0WR6x+UInVOZ{(WJ>{-PNWYuBrPSu3>1|nUT?o}ryt50iasSutC{2bwN%tB5x7OhRWc64q_ zp0QdMai8J@YrT>o#}(nrL`aL>dBg6RRBQ^+-US|5CC-c*3@t`Y&?Nr;-#s7K>X*uc zRTW3y_K)?$t3R9zr1*nhpyFU8S!77#$-~l1L04mSa}_AV7D{n zIFk&BC0r|>8yJU;OL!@85is#Z&WFLbQer*Bf`HXbU`-a3mR zlZte;QTaYA+OzD!@?x5VWhhij=##y!Xo8}?bs<9_%#i8zA$`V!yB2pk8Afnusk(6S zCxy}a%C8_a*}kHM6?4Zg@XI6nleX4no-V|!Hqxx!kyPfl}HWN@>XFNN|nwgol zt9(F@OzB@!5%Iul;+ohYyJwMR3}>`^qW|eCEE1Qq?&K{cpgYk@I zBc$Tkc5JVNWI^6m_tw4Yae%o~>vn6#V~3N0TS~ zjGX~*oV7-Mm6t!0@`|?bkvKC+Gq&8*(T#0YQ+fmqO921kdll=nhZJ)o@+7C_TsT1`wAKOlcl}FffnOTq?28GrG*}(XJBB34MCNF)`h9N zFW%+^puI5OS+amDb_!`G5N*feISX~G*hdy3oe2=SW4-pX?L*Zo?{c#G*2S)PT`@b^ zcv^+T09H7Q;U`waqDiLm2vQ(5H|UK^ye^RO7&rCN-5^cSdCkFp@_I7)w#^<)RawO% z5OGXLiltOSct5_cpn=oZlb2nMn7~{JLWTFiwD2G>HWwq?DG33S_Vr{kdi|Hbv^EER z&l`{m|ajr1*P+tT|% zdj{kdP0^%uO0{|=fW)UJcuOBTG+AS&tp11Qk`WK!Z_~+VLHirFWII92H_QyQSxbu0 zzhr{MGz(VkJ7A0XC@GI7eg(KRK>sKzzoex={CLryLuFdHN6QQS|F-|8Gw|_kI93+< zY?a#&vkL92ZVQ{Ii~47WQ>xVdw%|woM!10flw!t!r|R*Io4TyWXdE52USXXQ=vs%e z05&$0^n9Wia|?Z}^7&aH;_*^MG+B<9Vmyz;eEi+TgkJn*viR;ioV%kWM3hD~07_j3N-WUOQ`1{GS2vq(X`5RsfM#fuMbUR`{9_Dzqn(XA8*bk>nH zxIwf|eeLRUySzd-gAi;@mwJWV(};&Ob0eZjpx3|xEP#DsHCLDJ)4EISb0#Uohyr`K zV{7tT7OAs<{-%$(-vW9T$n3YBlwbYHJrcBNZC8?-wLO4-n{PDG5JDB%S{Xvh>^ESk z@UJ_z-i?+#L7p$A$@3uyW_b7f*Bp!Z}e94pDbOom!17vK(SNH-% znhCt!wq~!Wmh6?l;F|(_3g04s`maAdBWpx!24O$7tf*hE7Aw&0vRGo8&}G&9P)Dxn z5YcxP4^7kK7nr(eI$(Ysx+1}Sc!jZ;u&l1iYs%fY_6@jVy3GFKzqs8RD?I>m5^`R6# z`Xv(zdGQCXe84z1X;r@7!p&RF%gE!OA2;tNlCRC6i&AJK*oIsX`e4+Laew@rib1BZ)|b0BD?a#zbG45h@ha^! zGO;L?dL2AAod>U zN5hbXV^cY`%&F+w&TTrOUQ8|i>E4qc@i5*C)dtQ{rG)c%HFZDNWBO-KBlI^LcGE@) zi^3sd$`ef0di+&Cm*PP&`FEw>@hJ0J2|t)uW;1-HNtL7_R=@iD=o>pCug3sVa`1nXaf8c@Mu2c3&sDv+CQd^qF=DgIsC|$hC5t@hF z7*>60CZ_$~5q2y}P{+z`^owq47d8K?slm#G*7u>uJQ;0P+%qY8XxjOq#x6V{G}~ty zdi_q)n3*Zq6CpO5tdRol+iBmH641z7maKOtfsb!^2=39qk{=CysKcFT0>J^*P@dji zMx@jGEKQ?z83xdSkziG(UJM1zAw--PWGGMdYnYUc}uJS?`+n?Re%v80EirurM6ha-h zBv)Y6-HzKYETixlOu?^E|iS{`l$t+2zn$X>k{F&ioa~_w{$0whg$6jMuzX zst{2K3Y7S)1?vK!4CTaH;?)y?_p7%U^&PWhCq(dTx1pvr5c7;Lt?x5W9%!N!C$?As z#-H*3xeCfDnaw_6HCny?g*o(Km77rYj$#Qvs~q&SjA3j^M(>y+fEi?x;`P2bg@7Q4 z$i^>;ghV2sk)9{K38_`76k(1#3YDIY5Tmuo$pbjnB7Vp4{m`KeOYXT83H%LoiFx3D z0M>mV;xuBJ!Kec@f+tHLNr{Zu8sTY3X6)ssBw~QsuSEgcnF-&wmC`!P+-1pZ@?Uq4 zId_c=?=SCIhyuv}#8f)1k6V?|o;};e#HIN>;=$jT&)BE-S?lb^m%&jFjDzcGjsczi z{q%3swoNWbDm9PK$j9s3kA!9!4em^!?n1~V3oD-8Ediw$OiCtqpV*s9OO;u*xAr!r zmcy8-Eszn)uQ6%Ak_l5y6I$605LZQTZ0l_~RA`yaJ{0e^R1-kyq=gPzX0dpw#x(39 zuXI3bt7yw%Jnjg(CZqpYKb&~oo>egW;3Ya>oV`*a;Iv3vF%kuyAT~D;i(7Dnf}8cB zx0UGzxnhev!ZQ<3JyT8=#1TbK*k`Ia(D&p|Zcv2Qw#A>mCw~I3z@IuRHMM7FsL0Os z7E8>&y6rOiG0Eh5DtM9==OrX3$YKGStoWVx&@GEoA*o#NFxrhaw$*7KYuK4G^_yn- z93>(jsd{!h+jyt}oHTM<~UAiM^7XuDDt{G+=@03t=J2S1+0Tf3?`I>D<0MfO|HJ+Th z+|*R0YjvaS>T~MgbUb+njEM7lawU1jB>4GFu5HU%zPnep_Q9Q)NUiTB>!cY8il4bEBK4P2 zTi^7W6Yq19% z!51jR)IIRSz7PP>lw2 zix=)51RZ08W~c##={(|g&gJM5hf^@&H;0LOh{Mz3^(wP3xamG5VJp>@GO#N?b)FCV zJQoIvynUytr=RArPt(UdN&8RHo)h#ir{^{&XL&YuH0*t9`ka_vr{$I><#xnsKP5fR z!QL})08VH7+1GRKNv3Zg%FI=3aUWl=O0})ZF<37Vf*W@sB#~?ZfA<}7B{;%{LUJ*A zMNZxcIp<->+Ms~^^ursPcm*fV%BO4fYbtuVUU?@LsHe?HSbKiHHm2~a>$f+0%)sfM z6EqD^e_ip6c^sk@JF;U2cF)mvOYiZ#Ii5Gi^X6aaym|Ia7L*h{Cz z3OLIZYr=}|=XKM1BM!UMA8_F~0)2ZIJ%)y%ov8>*goQMt<@Q9}BKtY`vV(a5uwm_v zmR%XB{&*HC{J8$^U`0oNyMOgwCktT+V2FWmi9r+2L&!49qqfBhAzKvVu^?7aY%r1A zNR4oEM|yTg@bxZlm4}&BsocAa$Td7%1+8gUysx&cUSu*hcsPln1Cr0j_}CB28i+i}+Nz4Tj1=DJ8m4LV zsmF${`zsNrB592qZ5-p<>YE*7?HOaO3x^*wgoW~K$b^0{uXN3*ZT6|B)ZIV>hWL~7 zn(zL6>Y=7m-1DTXKHbJJr{#cBmdcheTwT zi`LxG4H|qhk9Up#lgJ1>)G-2g;Du233ypZFxj{<1Dn9vDtjm6YqN4ue!sq)2hEF}= z$P{f0B-$O$4+NLNRda?<3 z;5&{8iRC*OL)spx)--w)Yqu0@4gLN#<=VXt?n@DD_d4ijDB13He9v68J=j>0VQe{K ze7R-ZJ;Q9~T#qpNXDHe4b$riUwBO@cdu98c2U6BjKE68nKYk>NWvWkFa8r`ojMMrQ z>w}`*8cZ~e@+EIzUcSjql`^uaWDwvz%9Fc9JR~Ei`L0?D%6gc-p>x$p>e5z?UGKMX z`+OZLxkYsR-;2nl1Ma+U)%?U9JeC4>>u z1aRL2ksJ)0ZJtZ7jMCPL{y{fTpXP?N6+5%~_>vMbz?|#{D(5_tRPty|R7|6Yq(}>~ zfS7&Hxj#P?nXor439Icz(R~V{dlW6k$%ioIb5#FH;PCWi;UUALj=SNazd58mv%J+a$}EP{Mw!B&Z$4}Z##F2euW=Ml7o%B; z2N;3~`2xxu>b~e-RA%mFx^L+)Jj#eaiMtBLB6e= z1ABZ*x2sotQ@&o=HHe6q(jDs+n}%$>bG9lgx)qENMbk`RNkyymM))|E(*FC%^fMe` zPY)KQY&xvJJ$Q39PQk`BzyK->RsUf0BdS~$Z){iHqTfN6)D8kwwT-sLwGX+fVTn;# zSWhQj6^jTZtbr?OCpiTwxv;X5OGRjDSxSy5QRH*TBlqU0x#|FEb%xQ4PEWVRO zoFU_aVv>Y{A&!=wfkwcmOGT6rNudXt0^^B#0GQdD=TBuKRX9k%u9a*_Wf(D~%EQ4F zEym2%!)(z^t_M4;vW&&4Ur817XhrUhX|lF-clH(5+iY3Kb6gL+%@*5dmEsA{IE}88 zjLG}9iowstw{TtUY_%2*Sgal>&#(lM@$0b97!bv21nXEV77(z|w!01dmT^XK`z5YO zK%*d!(5k3N_P_&VhBXRyn8fqMpsL zApj-RO(w<_qKJ^X_ZAm4wD#$4X6cr3PVbgyOK}#m`?03;iz$_gz3pH=Tew;}xG2;h zpGvmiTge@>@^y!!LZeWvitj3H#NwV+^2%6f8fK23ucZ%tNF9Q8VU>3HI$Z7}&b^UWyKt6KSS!;y2%~zr$%qfvaV8%y^=!pQ80Z%Jn4sn{T z4O@bE02CthJ3K>|qA-89E2gju%>?)>5l^rd8*fOH ziC%VPL}HfFkY?2RNpt_NTN^^8ROj?lnSfX){N=0T^~GIgkB$NvsnN$k(An)wuW@Lls=?DNN>ncFKYITCS|{cZDJQMELUa!I3l2aw_M z1kR4y&94bjfzaIYlm2{41AsL*Lxb*&%&6|qX_T($IW`xpSWGQX7AZ?Er`Nx{npJ-8 zk{l`nuz`eEH*d>QE2t=e@z6$H=ts-$yXV#pXS%p&@}9GY@)&PEzMaKZIkmc_BTW{3 zt8$VX0<+LivXH+egSc;Z_=!2m>gV(f>^jOSpn*v4naqe}fmkN|_o8iO6YaDz4M%KD4~EWoj!7WtOs_vfo0cv=9jvOomLQ z@=BXA{>hIrH(@J;z>r7x8m{<_ffMcOY58Fm}_oS{ZS*+gQe3StMKzVi(@ zZVpwq{Bb~YE6c(8eJ8Z3AYf^x#)u?YnU%*u&dq|IfOGc)iq?#V)?Xz3Uk!4yWeFCq z*Op-U`_nJM0brSjSildO6vqX8H1Hg+=X?#Y|DXe0Wwwr$w+X1*{&W87&C9y|=i>b0 z_0j(G7}qnl|7@{}Q+kB(w9EF2P_ejAV z5W$<(hfVM}CBd%6$ zR?98G5qKD}E0HA6iK^GtKGpF-47i70dKeDgiY%oEhsAR47)wVq;`bFxu>s+UDNjJ! zBy+?~4I-i1lXH2dShU#N45Z~IdluB6mi@7mH`|?1fXhXqXQmF(_+|f^wgNHO>qEj9 zkSuGW!7~9QumOGs6KQ`dTrwK!74@8Gd{gaH7oDMaL)3~y7OYrsXUugef*;VBl@zBE zqLbkxpwQrbkgbu>Ee#tJt2v~~$=u_--~zy0{O2`04L$4T?=3_`U?=3_0F`3aJZ8En zGtrAYiq_;o@Z7%9F?SlErzxNoHZw|X-m zNrQs6fk0veJ^&)IJElmgkFk)oS9v&|GYW+e;()hg8V-_MFH21dz-Pq4Nvqsf*Rt28y_P>wTv))OKDxi?)zM#MucN={ z=r8)x{Y9R^&ke8ndW}L(qrWkhUTTfH0qefmelq|`j zH93E60Rp}S1CYv7Jqv(Y+oXJ8b&E^{A_8z2JvRtMtkx=H@frDK`feWsU1SN(&`)JI&#)i zv;Ao+x6weVA@(txu5VdH8%%$XK)TynCu&?u|6*xp96DfOZK9fO$sANAiBFAfR*P@u zR~DjiY(%6|h5HC|r*jb7}@ zvrh(l_sM|`H$GPH4Qg~*zUy_myUnb`2Z*A}h`iCa)&!pI&Eg(LaJ+UfV(-CZO+2v8 zdQ8_F)EsWUZXt~|YPXrNTT-JAx%9hi+8cxzZr5(>bn(`9_?|5`?#&KwYv(3@{>o@(i(scl5u@O71nj?ZC|c9Zcz8Ia zlS!m$@7R595lzhtS2PLLirz7(4=7}aSktLw3nsN5vWEUT;8*3 zF}&?qTdj=^;9@5AfybgqHxuAD6_j_e(J%p?7klPr`a7fY{5d>Fi|OY^q1=y-AB(pe zfw7!J03E4TgMkPkgu`hf;8ZBZ=aE5`SKkx!k=qZm^U10Euk*^kURM6~su?}U0Aqg= zNyG8pLB*ISyHKilyH;X8dG?fYn;b+jT*oNIU+pN2Ok3J&Eca#o#47-BjkVye$W$aPt<#91grNN0mVC>?8@Mi_}4ypJkEL@ zh5><&hE%NLTvg&JfRnC^Orn2)8>KK)4at)^+M#RLF#9jmGaG9D?Ztn7b5Y0tdHL$i z5&!v7uIFw4HS28$^Y2Wzuxb5;pPP)o_{B}zuQKgCndujLJjC(~FSxw%ov~;@aMhea z@eq+jYis7fFH~Z+;V81&do@IxD-ttmIrUoPBtU!FirzDlJqRp*XztU^mJ<^41<0?N zqj}&YYRanp*qzf!zd6dPrZ~ zPid!Wv--3cs_X#=UE0DzRoJL9QK${D>wHaB9%Vo4%0hXKoPoERUOGc(8iAJZ#B?UG z4{mAWh1x#B6WFE6PC3nevwfhs-f^Zo=ed2BJLkA#h7HyK$`U3uGuN}@H;3e;);IiI|K{qkkK{@3ft(f;!&*K@Z2)YjY9Rv^4P z!*=Snpvuini%_)>b-PgI?$cR^Dr4}q5t+x&+8Yw~KmtR4CS2A&BA00zt;qx9%M}P= z<}F1;LLx!K(VRv!391}+L_TsUwE!UL0-U1>sSp>hE%WnD~ocFl)oCLvzrQrNSIeE7TkG= z+3(?L1jw|V!WIxU69e#m{EY0O#b!Z_bjpJ^4WwT^TL^uE+^~>K7PO@kZgjsjL6d+l zqtfJt6IvE`47;2&(+w87sgo`}NI;`@vk<9QOYc#n+VfNi&ZIu4+DSpf5F{%aO?&A} zd{w;q@&F7@OS%ALy8@as6PjiK!_b^7=sM4fBmiFal-TfC$w%+Fci<*ts?Z3Wvp#FC=6VNPt7cVHT zAXG;**c=76WyjGmfUQoIZu4wLv)tQ23lCT3f_+XA2L&+ou{9Eiurm+6uxl1@@7o?L z-E)+6A&8S_e5_a$pr**+&`8SFI9GtSL2U6RIu>ONM51`e3SrMI!aTv3S~3psDtOoH zJs(Rw!q28g+elDQWL<*k_v~70RB`Opl~6IOSw^aN8|-M!gKJ$GG5!352-h?IyN{=^ z3!%j})3|7qzF~0@EWezKa9wW3&i!`1DBs|UL{u)BJayl+#TrmMY%A7KtRf?daz#ex zr>3p}22bTl#ABX8Dd^u@W^C75%vOo@Nf|+fwK-grHYK8}~4 zR*sjCZjM*4hK|=zJ>Bg_&k2gxb~<~14;sXfei_T{eW(78SHBkDG)6C7zIT8I33z9X z-W{^Xg!OCpc=ZTlc=?KC)u)FqD~}C+2;CnqFAD%(TiOBe>azymwNIM>Ufz?^Z69dp zp2xK9W-Gw!5iJII`PmKd@}_RL4FRvMED62C*@4IUjH}bO&@?Vj3&SDD<-^eWYz_@W z^R_(nACJ48jUMyXXNzbWo}WdccW{Ab3VX3jxMTL2(_R||USHbb_$)0Lc=^~d@Y>;U z^%4l%EgN|4$-aSCyOjg4Zd-?a#>3))m)F|rlZ1z?x($HQ-XLmHMD@r{S9tw`VjMP6 zi{nzZ*zlm%KZr{04=Z@X3?kC`J_rZlRNmAp0sg zA=qAlU3`jJ=TKYU@)IXci^(Ps`tow~=0E)KjUvH{N1xM=YSW?2tMmC929 z{Vki6D)nBd3~fLAS~}B8tBvRwCPvM*pm4QW(mYR9CK-(z_M|`Ms)Ga`A@h9@kI8@~ zodV||s$p|g7$7P$yIyQmYbK06x|;&C0vOH0vP|@==aUBfl={f~#NIx=uvfp`ThtEr%yLL}eNg$Bv$rWgn<4}Gi|f?4VHI%oB3YvI`HSMPA!GzJp35a?#()zYaT z9txIcHe|PWUs3f6rr5D{&F=1O6dA-`yc1EbR@a`U)4{$8xADr7vc_6~b&PowaZ^qR zey~z5bdD8a)rKuTtazjqv~*n-tv2+Xi_k+eyDX~z80)ryQxNz;!sD2QoMtRqn_4W8 zO8g*s#;Sek{}%25*EObDEY>6n@dUkL_e?4_mE!Zd3@TS{rFv=trx}g)nC^kLMMAqi6+?C5Q_MBR9~8C zKP6G;>^64!{q5~kzu2rLK(9TTB!vhT1WYL?(r0-6Nb!)7%jvZ`#dCrx^1t++&Y%zd z+<%B)pI{u)<+69$Ht66XYY+@ix?Jj&8X9yEU^RI>M;EjaF-%#zl7xhPPPyz;H|_PS z=Ftk_4`?Y#;Ac)7njLnY)<1#88=Y1YEiMe{@(^Qvzpd0>8&&$9mt7O~}c3##nfq+JSLl33x_67&MwK) zzXH-ZusR2qx}M(X6P~7#R-tSa~=CI`YsS9 zLTsLV%gx@^+>Ka-eb7l4&`*~S>-*Bwu89XwkK2XV7eS?zH_}VC)#sxpB=z) zwuQ^A?|kcXlX=eE9$jP4$0_!l-Cn_b*B9p05~95tP;01t=;KL^YJfQIMhba@!E~wziLvOrOWmdc?OOBzPTh1#&+u-&FfsVQN;VcCgPtF!HFr-+L_LUI(> z5t0M0BP56I!4Z<<2+47T6nsq zOi3!PV@lF7C28Y<)|-ttHjnoaiCIQNno;K`Ez^A6+7O6=q2pdrnUHkJ%r9SkQI|Q! z^&zbfZIy|b|BgrCn#R#yzA>3hCT}h-;J=f}r2gNRuU@|V>ipun$*c3%7q8CWd^Lgp zenlpG`FhWltBlI8COdztKDaOB8jVI@Ll_wOn>+bm)0F?hqyjc$mjydR8R_iq&q|Ac z_vdq#(etmZQ5qzo7bM7KL`H%vX~rJtdZaR%gj9wjo~VpQ(dhpC?EGv3>x+y&6nuEe zvsFGn3q-7lqSj>lcT7 zG>en~Ic3Nj`Y83MhWWEd%7fRQnxlSMSLOWAn99^x|M?I7=e{I>zVrXhm&&!4My_t&s;@H^r;*mQzc2P4ZYfw7_#@B0Hx|I;n~bdJJtH((!?R>wM2~@3 zOqF7?%xfKy6;*FVkjE^kX1fL=PqOdHU8I#HP&gi^TsJ%&B@u za Date: Mon, 16 Dec 2024 08:10:40 +0100 Subject: [PATCH 02/44] fix: schemas --- Makefile | 3 +- hack/test.sh | 4 +- traefik-crds/.schema.yaml | 13 + .../gateway-standard-install-v1.2.0.yaml} | 0 .../gateway_api/gateway-standard-install.yaml | 10345 ++++++++++++++++ traefik-crds/kustomization.yaml | 4 +- traefik-crds/values.schema.json | 25 + traefik-crds/values.yaml | 6 +- .schema.yaml => traefik/.schema.yaml | 4 +- traefik/charts/traefik-crds-0.0.1.tgz | Bin 125870 -> 126070 bytes traefik/values.schema.json | 12 +- traefik/values.yaml | 6 +- 12 files changed, 10400 insertions(+), 22 deletions(-) create mode 100644 traefik-crds/.schema.yaml rename traefik-crds/crds-files/{gateway/gateway-standard-install.yaml => gateway_api/gateway-standard-install-v1.2.0.yaml} (100%) create mode 100644 traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml create mode 100644 traefik-crds/values.schema.json rename .schema.yaml => traefik/.schema.yaml (79%) diff --git a/Makefile b/Makefile index 43ffaf01f..bfb25b4a3 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,8 @@ test-install: # Requires to install schema generation plugin beforehand # $ helm plugin install https://github.com/losisin/helm-values-schema-json.git schema: - helm schema + cd traefik && helm schema + cd traefik-crds && helm schema changelog: @echo "== Updating Changelogs..." diff --git a/hack/test.sh b/hack/test.sh index 49933bd06..2909b29ef 100644 --- a/hack/test.sh +++ b/hack/test.sh @@ -1,4 +1,4 @@ #!/bin/bash -/usr/bin/helm unittest --color ./traefik; -/usr/bin/helm unittest --color ./traefik-crds; +/usr/bin/helm unittest --color ./traefik +/usr/bin/helm unittest --color ./traefik-crds diff --git a/traefik-crds/.schema.yaml b/traefik-crds/.schema.yaml new file mode 100644 index 000000000..c71d1b799 --- /dev/null +++ b/traefik-crds/.schema.yaml @@ -0,0 +1,13 @@ +# Required +input: + - values.yaml + +draft: 2020 +indent: 4 +output: values.schema.json + +schemaRoot: + id: https://traefik.io/traefik-crds-helm-chart.schema.json + title: Traefik CRDs Helm Chart + description: The Cloud Native Application Proxy + additionalProperties: true diff --git a/traefik-crds/crds-files/gateway/gateway-standard-install.yaml b/traefik-crds/crds-files/gateway_api/gateway-standard-install-v1.2.0.yaml similarity index 100% rename from traefik-crds/crds-files/gateway/gateway-standard-install.yaml rename to traefik-crds/crds-files/gateway_api/gateway-standard-install-v1.2.0.yaml diff --git a/traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml b/traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml new file mode 100644 index 000000000..5bf4f3032 --- /dev/null +++ b/traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml @@ -0,0 +1,10345 @@ +# Copyright 2024 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Gateway API Standard channel install +# +--- +# +# config/crd/standard/gateway.networking.k8s.io_gatewayclasses.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: gatewayclasses.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: GatewayClass + listKind: GatewayClassList + plural: gatewayclasses + shortNames: + - gc + singular: gatewayclass + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.controllerName + name: Controller + type: string + - jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.description + name: Description + priority: 1 + type: string + name: v1 + schema: + openAPIV3Schema: + description: |- + GatewayClass describes a class of Gateways available to the user for creating + Gateway resources. + + It is recommended that this resource be used as a template for Gateways. This + means that a Gateway is based on the state of the GatewayClass at the time it + was created and changes to the GatewayClass or associated parameters are not + propagated down to existing Gateways. This recommendation is intended to + limit the blast radius of changes to GatewayClass or associated parameters. + If implementations choose to propagate GatewayClass changes to existing + Gateways, that MUST be clearly documented by the implementation. + + Whenever one or more Gateways are using a GatewayClass, implementations SHOULD + add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the + associated GatewayClass. This ensures that a GatewayClass associated with a + Gateway is not deleted while in use. + + GatewayClass is a Cluster level resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of GatewayClass. + properties: + controllerName: + description: |- + ControllerName is the name of the controller that is managing Gateways of + this class. The value of this field MUST be a domain prefixed path. + + Example: "example.net/gateway-controller". + + This field is not mutable and cannot be empty. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + description: + description: Description helps describe a GatewayClass with more details. + maxLength: 64 + type: string + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the GatewayClass. This is optional if the + controller does not require any additional configuration. + + ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, + or an implementation-specific custom resource. The resource can be + cluster-scoped or namespace-scoped. + + If the referent cannot be found, refers to an unsupported kind, or when + the data within that resource is malformed, the GatewayClass SHOULD be + rejected with the "Accepted" status condition set to "False" and an + "InvalidParameters" reason. + + A Gateway for this GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + This field is required when referring to a Namespace-scoped resource and + MUST be unset when referring to a Cluster-scoped resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - controllerName + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Status defines the current state of GatewayClass. + + Implementations MUST populate status on all GatewayClass resources which + specify their controller name. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Conditions is the current status from the controller for + this GatewayClass. + + Controllers should prefer to publish conditions using values + of GatewayClassConditionType for the type of each Condition. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.controllerName + name: Controller + type: string + - jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.description + name: Description + priority: 1 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + GatewayClass describes a class of Gateways available to the user for creating + Gateway resources. + + It is recommended that this resource be used as a template for Gateways. This + means that a Gateway is based on the state of the GatewayClass at the time it + was created and changes to the GatewayClass or associated parameters are not + propagated down to existing Gateways. This recommendation is intended to + limit the blast radius of changes to GatewayClass or associated parameters. + If implementations choose to propagate GatewayClass changes to existing + Gateways, that MUST be clearly documented by the implementation. + + Whenever one or more Gateways are using a GatewayClass, implementations SHOULD + add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the + associated GatewayClass. This ensures that a GatewayClass associated with a + Gateway is not deleted while in use. + + GatewayClass is a Cluster level resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of GatewayClass. + properties: + controllerName: + description: |- + ControllerName is the name of the controller that is managing Gateways of + this class. The value of this field MUST be a domain prefixed path. + + Example: "example.net/gateway-controller". + + This field is not mutable and cannot be empty. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + description: + description: Description helps describe a GatewayClass with more details. + maxLength: 64 + type: string + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the GatewayClass. This is optional if the + controller does not require any additional configuration. + + ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, + or an implementation-specific custom resource. The resource can be + cluster-scoped or namespace-scoped. + + If the referent cannot be found, refers to an unsupported kind, or when + the data within that resource is malformed, the GatewayClass SHOULD be + rejected with the "Accepted" status condition set to "False" and an + "InvalidParameters" reason. + + A Gateway for this GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + This field is required when referring to a Namespace-scoped resource and + MUST be unset when referring to a Cluster-scoped resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - controllerName + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Status defines the current state of GatewayClass. + + Implementations MUST populate status on all GatewayClass resources which + specify their controller name. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Conditions is the current status from the controller for + this GatewayClass. + + Controllers should prefer to publish conditions using values + of GatewayClassConditionType for the type of each Condition. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +# +# config/crd/standard/gateway.networking.k8s.io_gateways.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: gateways.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gtw + singular: gateway + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.gatewayClassName + name: Class + type: string + - jsonPath: .status.addresses[*].value + name: Address + type: string + - jsonPath: .status.conditions[?(@.type=="Programmed")].status + name: Programmed + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + Gateway represents an instance of a service-traffic handling infrastructure + by binding Listeners to a set of IP addresses. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Gateway. + properties: + addresses: + description: |+ + Addresses requested for this Gateway. This is optional and behavior can + depend on the implementation. If a value is set in the spec and the + requested address is invalid or unavailable, the implementation MUST + indicate this in the associated entry in GatewayStatus.Addresses. + + The Addresses field represents a request for the address(es) on the + "outside of the Gateway", that traffic bound for this Gateway will use. + This could be the IP address or hostname of an external load balancer or + other networking infrastructure, or some other address that traffic will + be sent to. + + If no Addresses are specified, the implementation MAY schedule the + Gateway in an implementation-specific manner, assigning an appropriate + set of Addresses. + + The implementation MUST bind all Listeners to every GatewayAddress that + it assigns to the Gateway and add a corresponding entry in + GatewayStatus.Addresses. + + Support: Extended + + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + gatewayClassName: + description: |- + GatewayClassName used for this Gateway. This is the name of a + GatewayClass resource. + maxLength: 253 + minLength: 1 + type: string + infrastructure: + description: |- + Infrastructure defines infrastructure level attributes about this Gateway instance. + + Support: Extended + properties: + annotations: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Annotations that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources. + For other implementations, this refers to any relevant (implementation specific) "annotations" concepts. + + An implementation may chose to add additional implementation-specific annotations as they see fit. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Annotation keys must be in the form of an optional + DNS subdomain prefix followed by a required name segment of + up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the annotation key's prefix must be a + DNS subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + labels: + additionalProperties: + description: |- + LabelValue is the value of a label in the Gateway API. This is used for validation + of maps such as Gateway infrastructure labels. This matches the Kubernetes + label validation rules: + * must be 63 characters or less (can be empty), + * unless empty, must begin and end with an alphanumeric character ([a-z0-9A-Z]), + * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. + + Valid values include: + + * MyValue + * my.name + * 123-my-value + maxLength: 63 + minLength: 0 + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + description: |- + Labels that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources. + For other implementations, this refers to any relevant (implementation specific) "labels" concepts. + + An implementation may chose to add additional implementation-specific labels as they see fit. + + If an implementation maps these labels to Pods, or any other resource that would need to be recreated when labels + change, it SHOULD clearly warn about this behavior in documentation. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Label keys must be in the form of an optional DNS subdomain + prefix followed by a required name segment of up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the label key's prefix must be a DNS + subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the Gateway. This is optional if the + controller does not require any additional configuration. + + This follows the same semantics as GatewayClass's `parametersRef`, but on a per-Gateway basis + + The Gateway's GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + type: object + listeners: + description: |- + Listeners associated with this Gateway. Listeners define + logical endpoints that are bound on this Gateway's addresses. + At least one Listener MUST be specified. + + Each Listener in a set of Listeners (for example, in a single Gateway) + MUST be _distinct_, in that a traffic flow MUST be able to be assigned to + exactly one listener. (This section uses "set of Listeners" rather than + "Listeners in a single Gateway" because implementations MAY merge configuration + from multiple Gateways onto a single data plane, and these rules _also_ + apply in that case). + + Practically, this means that each listener in a set MUST have a unique + combination of Port, Protocol, and, if supported by the protocol, Hostname. + + Some combinations of port, protocol, and TLS settings are considered + Core support and MUST be supported by implementations based on their + targeted conformance profile: + + HTTP Profile + + 1. HTTPRoute, Port: 80, Protocol: HTTP + 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided + + TLS Profile + + 1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough + + "Distinct" Listeners have the following property: + + The implementation can match inbound requests to a single distinct + Listener. When multiple Listeners share values for fields (for + example, two Listeners with the same Port value), the implementation + can match requests to only one of the Listeners using other + Listener fields. + + For example, the following Listener scenarios are distinct: + + 1. Multiple Listeners with the same Port that all use the "HTTP" + Protocol that all have unique Hostname values. + 2. Multiple Listeners with the same Port that use either the "HTTPS" or + "TLS" Protocol that all have unique Hostname values. + 3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener + with the same Protocol has the same Port value. + + Some fields in the Listener struct have possible values that affect + whether the Listener is distinct. Hostname is particularly relevant + for HTTP or HTTPS protocols. + + When using the Hostname value to select between same-Port, same-Protocol + Listeners, the Hostname value must be different on each Listener for the + Listener to be distinct. + + When the Listeners are distinct based on Hostname, inbound request + hostnames MUST match from the most specific to least specific Hostname + values to choose the correct Listener and its associated set of Routes. + + Exact matches must be processed before wildcard matches, and wildcard + matches must be processed before fallback (empty Hostname value) + matches. For example, `"foo.example.com"` takes precedence over + `"*.example.com"`, and `"*.example.com"` takes precedence over `""`. + + Additionally, if there are multiple wildcard entries, more specific + wildcard entries must be processed before less specific wildcard entries. + For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`. + The precise definition here is that the higher the number of dots in the + hostname to the right of the wildcard character, the higher the precedence. + + The wildcard character will match any number of characters _and dots_ to + the left, however, so `"*.example.com"` will match both + `"foo.bar.example.com"` _and_ `"bar.example.com"`. + + If a set of Listeners contains Listeners that are not distinct, then those + Listeners are Conflicted, and the implementation MUST set the "Conflicted" + condition in the Listener Status to "True". + + Implementations MAY choose to accept a Gateway with some Conflicted + Listeners only if they only accept the partial Listener set that contains + no Conflicted Listeners. To put this another way, implementations may + accept a partial Listener set only if they throw out *all* the conflicting + Listeners. No picking one of the conflicting listeners as the winner. + This also means that the Gateway must have at least one non-conflicting + Listener in this case, otherwise it violates the requirement that at + least one Listener must be present. + + The implementation MUST set a "ListenersNotValid" condition on the + Gateway Status when the Gateway contains Conflicted Listeners whether or + not they accept the Gateway. That Condition SHOULD clearly + indicate in the Message which Listeners are conflicted, and which are + Accepted. Additionally, the Listener status for those listeners SHOULD + indicate which Listeners are conflicted and not Accepted. + + A Gateway's Listeners are considered "compatible" if: + + 1. They are distinct. + 2. The implementation can serve them in compliance with the Addresses + requirement that all Listeners are available on all assigned + addresses. + + Compatible combinations in Extended support are expected to vary across + implementations. A combination that is compatible for one implementation + may not be compatible for another. + + For example, an implementation that cannot serve both TCP and UDP listeners + on the same address, or cannot mix HTTPS and generic TLS listens on the same port + would not consider those cases compatible, even though they are distinct. + + Note that requests SHOULD match at most one Listener. For example, if + Listeners are defined for "foo.example.com" and "*.example.com", a + request to "foo.example.com" SHOULD only be routed using routes attached + to the "foo.example.com" Listener (and not the "*.example.com" Listener). + This concept is known as "Listener Isolation". Implementations that do + not support Listener Isolation MUST clearly document this. + + Implementations MAY merge separate Gateways onto a single set of + Addresses if all Listeners across all Gateways are compatible. + + Support: Core + items: + description: |- + Listener embodies the concept of a logical endpoint where a Gateway accepts + network connections. + properties: + allowedRoutes: + default: + namespaces: + from: Same + description: |- + AllowedRoutes defines the types of routes that MAY be attached to a + Listener and the trusted namespaces where those Route resources MAY be + present. + + Although a client request may match multiple route rules, only one rule + may ultimately receive the request. Matching precedence MUST be + determined in order of the following criteria: + + * The most specific match as defined by the Route type. + * The oldest Route based on creation timestamp. For example, a Route with + a creation timestamp of "2020-09-08 01:02:03" is given precedence over + a Route with a creation timestamp of "2020-09-08 01:02:04". + * If everything else is equivalent, the Route appearing first in + alphabetical order (namespace/name) should be given precedence. For + example, foo/bar is given precedence over foo/baz. + + All valid rules within a Route attached to this Listener should be + implemented. Invalid Route rules can be ignored (sometimes that will mean + the full Route). If a Route rule transitions from valid to invalid, + support for that Route rule should be dropped to ensure consistency. For + example, even if a filter specified by a Route rule is invalid, the rest + of the rules within that Route should still be supported. + + Support: Core + properties: + kinds: + description: |- + Kinds specifies the groups and kinds of Routes that are allowed to bind + to this Gateway Listener. When unspecified or empty, the kinds of Routes + selected are determined using the Listener protocol. + + A RouteGroupKind MUST correspond to kinds of Routes that are compatible + with the application protocol specified in the Listener's Protocol field. + If an implementation does not support or recognize this resource type, it + MUST set the "ResolvedRefs" condition to False for this Listener with the + "InvalidRouteKinds" reason. + + Support: Core + items: + description: RouteGroupKind indicates the group and kind + of a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + namespaces: + default: + from: Same + description: |- + Namespaces indicates namespaces from which Routes may be attached to this + Listener. This is restricted to the namespace of this Gateway by default. + + Support: Core + properties: + from: + default: Same + description: |- + From indicates where Routes will be selected for this Gateway. Possible + values are: + + * All: Routes in all namespaces may be used by this Gateway. + * Selector: Routes in namespaces selected by the selector may be used by + this Gateway. + * Same: Only Routes in the same namespace may be used by this Gateway. + + Support: Core + enum: + - All + - Selector + - Same + type: string + selector: + description: |- + Selector must be specified when From is set to "Selector". In that case, + only Routes in Namespaces matching this Selector will be selected by this + Gateway. This field is ignored for other values of "From". + + Support: Core + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: object + hostname: + description: |- + Hostname specifies the virtual hostname to match for protocol types that + define this concept. When unspecified, all hostnames are matched. This + field is ignored for protocols that don't require hostname based + matching. + + Implementations MUST apply Hostname matching appropriately for each of + the following protocols: + + * TLS: The Listener Hostname MUST match the SNI. + * HTTP: The Listener Hostname MUST match the Host header of the request. + * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP + protocol layers as described above. If an implementation does not + ensure that both the SNI and Host header match the Listener hostname, + it MUST clearly document that. + + For HTTPRoute and TLSRoute resources, there is an interaction with the + `spec.hostnames` array. When both listener and route specify hostnames, + there MUST be an intersection between the values for a Route to be + accepted. For more information, refer to the Route specific Hostnames + documentation. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + name: + description: |- + Name is the name of the Listener. This name MUST be unique within a + Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: |- + Port is the network port. Multiple listeners may use the + same port, subject to the Listener compatibility rules. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: |- + Protocol specifies the network protocol this listener expects to receive. + + Support: Core + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ + type: string + tls: + description: |- + TLS is the TLS configuration for the Listener. This field is required if + the Protocol field is "HTTPS" or "TLS". It is invalid to set this field + if the Protocol field is "HTTP", "TCP", or "UDP". + + The association of SNIs to Certificate defined in GatewayTLSConfig is + defined based on the Hostname field for this listener. + + The GatewayClass MUST use the longest matching SNI out of all + available certificates for any TLS handshake. + + Support: Core + properties: + certificateRefs: + description: |- + CertificateRefs contains a series of references to Kubernetes objects that + contains TLS certificates and private keys. These certificates are used to + establish a TLS handshake for requests that match the hostname of the + associated listener. + + A single CertificateRef to a Kubernetes Secret has "Core" support. + Implementations MAY choose to support attaching multiple certificates to + a Listener, but this behavior is implementation-specific. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + This field is required to have at least one element when the mode is set + to "Terminate" (default) and is optional otherwise. + + CertificateRefs can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls + + Support: Implementation-specific (More than one reference or other resource types) + items: + description: |- + SecretObjectReference identifies an API object including its namespace, + defaulting to Secret. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + maxItems: 64 + type: array + mode: + default: Terminate + description: |- + Mode defines the TLS behavior for the TLS session initiated by the client. + There are two possible modes: + + - Terminate: The TLS session between the downstream client and the + Gateway is terminated at the Gateway. This mode requires certificates + to be specified in some way, such as populating the certificateRefs + field. + - Passthrough: The TLS session is NOT terminated by the Gateway. This + implies that the Gateway can't decipher the TLS stream except for + the ClientHello message of the TLS protocol. The certificateRefs field + is ignored in this mode. + + Support: Core + enum: + - Terminate + - Passthrough + type: string + options: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Options are a list of key/value pairs to enable extended TLS + configuration for each implementation. For example, configuring the + minimum TLS version or supported cipher suites. + + A set of common keys MAY be defined by the API in the future. To avoid + any ambiguity, implementation-specific definitions MUST use + domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by Gateway API. + + Support: Implementation-specific + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs or options must be specified when + mode is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 || size(self.options) > 0 : true' + required: + - name + - port + - protocol + type: object + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must not be specified for protocols ['HTTP', 'TCP', + 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: tls mode must be Terminate for protocol HTTPS + rule: 'self.all(l, (l.protocol == ''HTTPS'' && has(l.tls)) ? (l.tls.mode + == '''' || l.tls.mode == ''Terminate'') : true)' + - message: hostname must not be specified for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + required: + - gatewayClassName + - listeners + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: Status defines the current state of Gateway. + properties: + addresses: + description: |+ + Addresses lists the network addresses that have been bound to the + Gateway. + + This list may differ from the addresses provided in the spec under some + conditions: + + * no addresses are specified, all addresses are dynamically assigned + * a combination of specified and dynamic addresses are assigned + * a specified address was unusable (e.g. already in use) + + items: + description: GatewayStatusAddress describes a network address that + is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: |- + Conditions describe the current conditions of the Gateway. + + Implementations should prefer to express Gateway conditions + using the `GatewayConditionType` and `GatewayConditionReason` + constants so that operators and tools can converge on a common + vocabulary to describe Gateway state. + + Known condition types are: + + * "Accepted" + * "Programmed" + * "Ready" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + listeners: + description: Listeners provide status for each unique listener port + defined in the Spec. + items: + description: ListenerStatus is the status associated with a Listener. + properties: + attachedRoutes: + description: |- + AttachedRoutes represents the total number of Routes that have been + successfully attached to this Listener. + + Successful attachment of a Route to a Listener is based solely on the + combination of the AllowedRoutes field on the corresponding Listener + and the Route's ParentRefs field. A Route is successfully attached to + a Listener when it is selected by the Listener's AllowedRoutes field + AND the Route has a valid ParentRef selecting the whole Gateway + resource or a specific Listener as a parent resource (more detail on + attachment semantics can be found in the documentation on the various + Route kinds ParentRefs fields). Listener or Route status does not impact + successful attachment, i.e. the AttachedRoutes field count MUST be set + for Listeners with condition Accepted: false and MUST count successfully + attached Routes that may themselves have Accepted: false conditions. + + Uses for this field include troubleshooting Route attachment and + measuring blast radius/impact of changes to a Listener. + format: int32 + type: integer + conditions: + description: Conditions describe the current condition of this + listener. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: Name is the name of the Listener that this status + corresponds to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + supportedKinds: + description: |- + SupportedKinds is the list indicating the Kinds supported by this + listener. This MUST represent the kinds an implementation supports for + that Listener configuration. + + If kinds are specified in Spec that are not supported, they MUST NOT + appear in this list and an implementation MUST set the "ResolvedRefs" + condition to "False" with the "InvalidRouteKinds" reason. If both valid + and invalid Route kinds are specified, the implementation MUST + reference the valid Route kinds that have been specified. + items: + description: RouteGroupKind indicates the group and kind of + a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + required: + - attachedRoutes + - conditions + - name + - supportedKinds + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.gatewayClassName + name: Class + type: string + - jsonPath: .status.addresses[*].value + name: Address + type: string + - jsonPath: .status.conditions[?(@.type=="Programmed")].status + name: Programmed + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + Gateway represents an instance of a service-traffic handling infrastructure + by binding Listeners to a set of IP addresses. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Gateway. + properties: + addresses: + description: |+ + Addresses requested for this Gateway. This is optional and behavior can + depend on the implementation. If a value is set in the spec and the + requested address is invalid or unavailable, the implementation MUST + indicate this in the associated entry in GatewayStatus.Addresses. + + The Addresses field represents a request for the address(es) on the + "outside of the Gateway", that traffic bound for this Gateway will use. + This could be the IP address or hostname of an external load balancer or + other networking infrastructure, or some other address that traffic will + be sent to. + + If no Addresses are specified, the implementation MAY schedule the + Gateway in an implementation-specific manner, assigning an appropriate + set of Addresses. + + The implementation MUST bind all Listeners to every GatewayAddress that + it assigns to the Gateway and add a corresponding entry in + GatewayStatus.Addresses. + + Support: Extended + + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + gatewayClassName: + description: |- + GatewayClassName used for this Gateway. This is the name of a + GatewayClass resource. + maxLength: 253 + minLength: 1 + type: string + infrastructure: + description: |- + Infrastructure defines infrastructure level attributes about this Gateway instance. + + Support: Extended + properties: + annotations: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Annotations that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources. + For other implementations, this refers to any relevant (implementation specific) "annotations" concepts. + + An implementation may chose to add additional implementation-specific annotations as they see fit. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Annotation keys must be in the form of an optional + DNS subdomain prefix followed by a required name segment of + up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the annotation key's prefix must be a + DNS subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + labels: + additionalProperties: + description: |- + LabelValue is the value of a label in the Gateway API. This is used for validation + of maps such as Gateway infrastructure labels. This matches the Kubernetes + label validation rules: + * must be 63 characters or less (can be empty), + * unless empty, must begin and end with an alphanumeric character ([a-z0-9A-Z]), + * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. + + Valid values include: + + * MyValue + * my.name + * 123-my-value + maxLength: 63 + minLength: 0 + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + description: |- + Labels that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources. + For other implementations, this refers to any relevant (implementation specific) "labels" concepts. + + An implementation may chose to add additional implementation-specific labels as they see fit. + + If an implementation maps these labels to Pods, or any other resource that would need to be recreated when labels + change, it SHOULD clearly warn about this behavior in documentation. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Label keys must be in the form of an optional DNS subdomain + prefix followed by a required name segment of up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the label key's prefix must be a DNS + subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the Gateway. This is optional if the + controller does not require any additional configuration. + + This follows the same semantics as GatewayClass's `parametersRef`, but on a per-Gateway basis + + The Gateway's GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + type: object + listeners: + description: |- + Listeners associated with this Gateway. Listeners define + logical endpoints that are bound on this Gateway's addresses. + At least one Listener MUST be specified. + + Each Listener in a set of Listeners (for example, in a single Gateway) + MUST be _distinct_, in that a traffic flow MUST be able to be assigned to + exactly one listener. (This section uses "set of Listeners" rather than + "Listeners in a single Gateway" because implementations MAY merge configuration + from multiple Gateways onto a single data plane, and these rules _also_ + apply in that case). + + Practically, this means that each listener in a set MUST have a unique + combination of Port, Protocol, and, if supported by the protocol, Hostname. + + Some combinations of port, protocol, and TLS settings are considered + Core support and MUST be supported by implementations based on their + targeted conformance profile: + + HTTP Profile + + 1. HTTPRoute, Port: 80, Protocol: HTTP + 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided + + TLS Profile + + 1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough + + "Distinct" Listeners have the following property: + + The implementation can match inbound requests to a single distinct + Listener. When multiple Listeners share values for fields (for + example, two Listeners with the same Port value), the implementation + can match requests to only one of the Listeners using other + Listener fields. + + For example, the following Listener scenarios are distinct: + + 1. Multiple Listeners with the same Port that all use the "HTTP" + Protocol that all have unique Hostname values. + 2. Multiple Listeners with the same Port that use either the "HTTPS" or + "TLS" Protocol that all have unique Hostname values. + 3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener + with the same Protocol has the same Port value. + + Some fields in the Listener struct have possible values that affect + whether the Listener is distinct. Hostname is particularly relevant + for HTTP or HTTPS protocols. + + When using the Hostname value to select between same-Port, same-Protocol + Listeners, the Hostname value must be different on each Listener for the + Listener to be distinct. + + When the Listeners are distinct based on Hostname, inbound request + hostnames MUST match from the most specific to least specific Hostname + values to choose the correct Listener and its associated set of Routes. + + Exact matches must be processed before wildcard matches, and wildcard + matches must be processed before fallback (empty Hostname value) + matches. For example, `"foo.example.com"` takes precedence over + `"*.example.com"`, and `"*.example.com"` takes precedence over `""`. + + Additionally, if there are multiple wildcard entries, more specific + wildcard entries must be processed before less specific wildcard entries. + For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`. + The precise definition here is that the higher the number of dots in the + hostname to the right of the wildcard character, the higher the precedence. + + The wildcard character will match any number of characters _and dots_ to + the left, however, so `"*.example.com"` will match both + `"foo.bar.example.com"` _and_ `"bar.example.com"`. + + If a set of Listeners contains Listeners that are not distinct, then those + Listeners are Conflicted, and the implementation MUST set the "Conflicted" + condition in the Listener Status to "True". + + Implementations MAY choose to accept a Gateway with some Conflicted + Listeners only if they only accept the partial Listener set that contains + no Conflicted Listeners. To put this another way, implementations may + accept a partial Listener set only if they throw out *all* the conflicting + Listeners. No picking one of the conflicting listeners as the winner. + This also means that the Gateway must have at least one non-conflicting + Listener in this case, otherwise it violates the requirement that at + least one Listener must be present. + + The implementation MUST set a "ListenersNotValid" condition on the + Gateway Status when the Gateway contains Conflicted Listeners whether or + not they accept the Gateway. That Condition SHOULD clearly + indicate in the Message which Listeners are conflicted, and which are + Accepted. Additionally, the Listener status for those listeners SHOULD + indicate which Listeners are conflicted and not Accepted. + + A Gateway's Listeners are considered "compatible" if: + + 1. They are distinct. + 2. The implementation can serve them in compliance with the Addresses + requirement that all Listeners are available on all assigned + addresses. + + Compatible combinations in Extended support are expected to vary across + implementations. A combination that is compatible for one implementation + may not be compatible for another. + + For example, an implementation that cannot serve both TCP and UDP listeners + on the same address, or cannot mix HTTPS and generic TLS listens on the same port + would not consider those cases compatible, even though they are distinct. + + Note that requests SHOULD match at most one Listener. For example, if + Listeners are defined for "foo.example.com" and "*.example.com", a + request to "foo.example.com" SHOULD only be routed using routes attached + to the "foo.example.com" Listener (and not the "*.example.com" Listener). + This concept is known as "Listener Isolation". Implementations that do + not support Listener Isolation MUST clearly document this. + + Implementations MAY merge separate Gateways onto a single set of + Addresses if all Listeners across all Gateways are compatible. + + Support: Core + items: + description: |- + Listener embodies the concept of a logical endpoint where a Gateway accepts + network connections. + properties: + allowedRoutes: + default: + namespaces: + from: Same + description: |- + AllowedRoutes defines the types of routes that MAY be attached to a + Listener and the trusted namespaces where those Route resources MAY be + present. + + Although a client request may match multiple route rules, only one rule + may ultimately receive the request. Matching precedence MUST be + determined in order of the following criteria: + + * The most specific match as defined by the Route type. + * The oldest Route based on creation timestamp. For example, a Route with + a creation timestamp of "2020-09-08 01:02:03" is given precedence over + a Route with a creation timestamp of "2020-09-08 01:02:04". + * If everything else is equivalent, the Route appearing first in + alphabetical order (namespace/name) should be given precedence. For + example, foo/bar is given precedence over foo/baz. + + All valid rules within a Route attached to this Listener should be + implemented. Invalid Route rules can be ignored (sometimes that will mean + the full Route). If a Route rule transitions from valid to invalid, + support for that Route rule should be dropped to ensure consistency. For + example, even if a filter specified by a Route rule is invalid, the rest + of the rules within that Route should still be supported. + + Support: Core + properties: + kinds: + description: |- + Kinds specifies the groups and kinds of Routes that are allowed to bind + to this Gateway Listener. When unspecified or empty, the kinds of Routes + selected are determined using the Listener protocol. + + A RouteGroupKind MUST correspond to kinds of Routes that are compatible + with the application protocol specified in the Listener's Protocol field. + If an implementation does not support or recognize this resource type, it + MUST set the "ResolvedRefs" condition to False for this Listener with the + "InvalidRouteKinds" reason. + + Support: Core + items: + description: RouteGroupKind indicates the group and kind + of a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + namespaces: + default: + from: Same + description: |- + Namespaces indicates namespaces from which Routes may be attached to this + Listener. This is restricted to the namespace of this Gateway by default. + + Support: Core + properties: + from: + default: Same + description: |- + From indicates where Routes will be selected for this Gateway. Possible + values are: + + * All: Routes in all namespaces may be used by this Gateway. + * Selector: Routes in namespaces selected by the selector may be used by + this Gateway. + * Same: Only Routes in the same namespace may be used by this Gateway. + + Support: Core + enum: + - All + - Selector + - Same + type: string + selector: + description: |- + Selector must be specified when From is set to "Selector". In that case, + only Routes in Namespaces matching this Selector will be selected by this + Gateway. This field is ignored for other values of "From". + + Support: Core + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: object + hostname: + description: |- + Hostname specifies the virtual hostname to match for protocol types that + define this concept. When unspecified, all hostnames are matched. This + field is ignored for protocols that don't require hostname based + matching. + + Implementations MUST apply Hostname matching appropriately for each of + the following protocols: + + * TLS: The Listener Hostname MUST match the SNI. + * HTTP: The Listener Hostname MUST match the Host header of the request. + * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP + protocol layers as described above. If an implementation does not + ensure that both the SNI and Host header match the Listener hostname, + it MUST clearly document that. + + For HTTPRoute and TLSRoute resources, there is an interaction with the + `spec.hostnames` array. When both listener and route specify hostnames, + there MUST be an intersection between the values for a Route to be + accepted. For more information, refer to the Route specific Hostnames + documentation. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + name: + description: |- + Name is the name of the Listener. This name MUST be unique within a + Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: |- + Port is the network port. Multiple listeners may use the + same port, subject to the Listener compatibility rules. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: |- + Protocol specifies the network protocol this listener expects to receive. + + Support: Core + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ + type: string + tls: + description: |- + TLS is the TLS configuration for the Listener. This field is required if + the Protocol field is "HTTPS" or "TLS". It is invalid to set this field + if the Protocol field is "HTTP", "TCP", or "UDP". + + The association of SNIs to Certificate defined in GatewayTLSConfig is + defined based on the Hostname field for this listener. + + The GatewayClass MUST use the longest matching SNI out of all + available certificates for any TLS handshake. + + Support: Core + properties: + certificateRefs: + description: |- + CertificateRefs contains a series of references to Kubernetes objects that + contains TLS certificates and private keys. These certificates are used to + establish a TLS handshake for requests that match the hostname of the + associated listener. + + A single CertificateRef to a Kubernetes Secret has "Core" support. + Implementations MAY choose to support attaching multiple certificates to + a Listener, but this behavior is implementation-specific. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + This field is required to have at least one element when the mode is set + to "Terminate" (default) and is optional otherwise. + + CertificateRefs can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls + + Support: Implementation-specific (More than one reference or other resource types) + items: + description: |- + SecretObjectReference identifies an API object including its namespace, + defaulting to Secret. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + maxItems: 64 + type: array + mode: + default: Terminate + description: |- + Mode defines the TLS behavior for the TLS session initiated by the client. + There are two possible modes: + + - Terminate: The TLS session between the downstream client and the + Gateway is terminated at the Gateway. This mode requires certificates + to be specified in some way, such as populating the certificateRefs + field. + - Passthrough: The TLS session is NOT terminated by the Gateway. This + implies that the Gateway can't decipher the TLS stream except for + the ClientHello message of the TLS protocol. The certificateRefs field + is ignored in this mode. + + Support: Core + enum: + - Terminate + - Passthrough + type: string + options: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Options are a list of key/value pairs to enable extended TLS + configuration for each implementation. For example, configuring the + minimum TLS version or supported cipher suites. + + A set of common keys MAY be defined by the API in the future. To avoid + any ambiguity, implementation-specific definitions MUST use + domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by Gateway API. + + Support: Implementation-specific + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs or options must be specified when + mode is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 || size(self.options) > 0 : true' + required: + - name + - port + - protocol + type: object + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must not be specified for protocols ['HTTP', 'TCP', + 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: tls mode must be Terminate for protocol HTTPS + rule: 'self.all(l, (l.protocol == ''HTTPS'' && has(l.tls)) ? (l.tls.mode + == '''' || l.tls.mode == ''Terminate'') : true)' + - message: hostname must not be specified for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + required: + - gatewayClassName + - listeners + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: Status defines the current state of Gateway. + properties: + addresses: + description: |+ + Addresses lists the network addresses that have been bound to the + Gateway. + + This list may differ from the addresses provided in the spec under some + conditions: + + * no addresses are specified, all addresses are dynamically assigned + * a combination of specified and dynamic addresses are assigned + * a specified address was unusable (e.g. already in use) + + items: + description: GatewayStatusAddress describes a network address that + is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: |- + Conditions describe the current conditions of the Gateway. + + Implementations should prefer to express Gateway conditions + using the `GatewayConditionType` and `GatewayConditionReason` + constants so that operators and tools can converge on a common + vocabulary to describe Gateway state. + + Known condition types are: + + * "Accepted" + * "Programmed" + * "Ready" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + listeners: + description: Listeners provide status for each unique listener port + defined in the Spec. + items: + description: ListenerStatus is the status associated with a Listener. + properties: + attachedRoutes: + description: |- + AttachedRoutes represents the total number of Routes that have been + successfully attached to this Listener. + + Successful attachment of a Route to a Listener is based solely on the + combination of the AllowedRoutes field on the corresponding Listener + and the Route's ParentRefs field. A Route is successfully attached to + a Listener when it is selected by the Listener's AllowedRoutes field + AND the Route has a valid ParentRef selecting the whole Gateway + resource or a specific Listener as a parent resource (more detail on + attachment semantics can be found in the documentation on the various + Route kinds ParentRefs fields). Listener or Route status does not impact + successful attachment, i.e. the AttachedRoutes field count MUST be set + for Listeners with condition Accepted: false and MUST count successfully + attached Routes that may themselves have Accepted: false conditions. + + Uses for this field include troubleshooting Route attachment and + measuring blast radius/impact of changes to a Listener. + format: int32 + type: integer + conditions: + description: Conditions describe the current condition of this + listener. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: Name is the name of the Listener that this status + corresponds to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + supportedKinds: + description: |- + SupportedKinds is the list indicating the Kinds supported by this + listener. This MUST represent the kinds an implementation supports for + that Listener configuration. + + If kinds are specified in Spec that are not supported, they MUST NOT + appear in this list and an implementation MUST set the "ResolvedRefs" + condition to "False" with the "InvalidRouteKinds" reason. If both valid + and invalid Route kinds are specified, the implementation MUST + reference the valid Route kinds that have been specified. + items: + description: RouteGroupKind indicates the group and kind of + a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + required: + - attachedRoutes + - conditions + - name + - supportedKinds + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +# +# config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: grpcroutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: GRPCRoute + listKind: GRPCRouteList + plural: grpcroutes + singular: grpcroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + GRPCRoute provides a way to route gRPC requests. This includes the capability + to match requests by hostname, gRPC service, gRPC method, or HTTP/2 header. + Filters can be used to specify additional processing steps. Backends specify + where matching requests will be routed. + + GRPCRoute falls under extended support within the Gateway API. Within the + following specification, the word "MUST" indicates that an implementation + supporting GRPCRoute must conform to the indicated requirement, but an + implementation not supporting this route type need not follow the requirement + unless explicitly indicated. + + Implementations supporting `GRPCRoute` with the `HTTPS` `ProtocolType` MUST + accept HTTP/2 connections without an initial upgrade from HTTP/1.1, i.e. via + ALPN. If the implementation does not support this, then it MUST set the + "Accepted" condition to "False" for the affected listener with a reason of + "UnsupportedProtocol". Implementations MAY also accept HTTP/2 connections + with an upgrade from HTTP/1. + + Implementations supporting `GRPCRoute` with the `HTTP` `ProtocolType` MUST + support HTTP/2 over cleartext TCP (h2c, + https://www.rfc-editor.org/rfc/rfc7540#section-3.1) without an initial + upgrade from HTTP/1.1, i.e. with prior knowledge + (https://www.rfc-editor.org/rfc/rfc7540#section-3.4). If the implementation + does not support this, then it MUST set the "Accepted" condition to "False" + for the affected listener with a reason of "UnsupportedProtocol". + Implementations MAY also accept HTTP/2 connections with an upgrade from + HTTP/1, i.e. without prior knowledge. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of GRPCRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames to match against the GRPC + Host header to select a GRPCRoute to process the request. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label MUST appear by itself as the first label. + + If a hostname is specified by both the Listener and GRPCRoute, there + MUST be at least one intersecting hostname for the GRPCRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches GRPCRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches GRPCRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `test.example.com` and `*.example.com` would both match. On the other + hand, `example.com` and `test.example.net` would not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and GRPCRoute have specified hostnames, any + GRPCRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + GRPCRoute specified `test.example.com` and `test.example.net`, + `test.example.net` MUST NOT be considered for a match. + + If both the Listener and GRPCRoute have specified hostnames, and none + match with the criteria above, then the GRPCRoute MUST NOT be accepted by + the implementation. The implementation MUST raise an 'Accepted' Condition + with a status of `False` in the corresponding RouteParentStatus. + + If a Route (A) of type HTTPRoute or GRPCRoute is attached to a + Listener and that listener already has another Route (B) of the other + type attached and the intersection of the hostnames of A and B is + non-empty, then the implementation MUST accept exactly one of these two + routes, determined by the following criteria, in order: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + The rejected Route MUST raise an 'Accepted' condition with a status of + 'False' in the corresponding RouteParentStatus. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''')) : true))' + - message: sectionName must be unique when parentRefs includes 2 or + more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)))) + rules: + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: + description: |- + GRPCRouteRule defines the semantics for matching a gRPC request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive an `UNAVAILABLE` status. + + See the GRPCBackendRef definition for the rules about what makes a single + GRPCBackendRef invalid. + + When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive an `UNAVAILABLE` status. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status. + Implementations may choose how that 50 percent is determined. + + Support: Core for Kubernetes Service + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + GRPCBackendRef defines how a GRPCRoute forwards a gRPC request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + properties: + filters: + description: |- + Filters defined at this level MUST be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in GRPCRouteRule.) + items: + description: |- + GRPCRouteFilter defines processing steps that must be completed during the + request or response lifecycle. GRPCRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + Support: Implementation-specific + + This filter can be used multiple times within the same rule. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + required: + - backendRef + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |+ + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations supporting GRPCRoute MUST support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` MUST be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + enum: + - ResponseHeaderModifier + - RequestHeaderModifier + - RequestMirror + - ExtensionRef + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations that support + GRPCRoute. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + If an implementation can not support a combination of filters, it must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + GRPCRouteFilter defines processing steps that must be completed during the + request or response lifecycle. GRPCRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + Support: Implementation-specific + + This filter can be used multiple times within the same rule. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + required: + - backendRef + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |+ + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations supporting GRPCRoute MUST support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` MUST be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + enum: + - ResponseHeaderModifier + - RequestHeaderModifier + - RequestMirror + - ExtensionRef + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + matches: + description: |- + Matches define conditions used for matching the rule against incoming + gRPC requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - method: + service: foo.bar + headers: + values: + version: 2 + - method: + service: foo.bar.v2 + ``` + + For a request to match against this rule, it MUST satisfy + EITHER of the two conditions: + + - service of foo.bar AND contains the header `version: 2` + - service of foo.bar.v2 + + See the documentation for GRPCRouteMatch on how to specify multiple + match conditions to be ANDed together. + + If no matches are specified, the implementation MUST match every gRPC request. + + Proxy or Load Balancer routing configuration generated from GRPCRoutes + MUST prioritize rules based on the following criteria, continuing on + ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes. + Precedence MUST be given to the rule with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + * Characters in a matching service. + * Characters in a matching method. + * Header matches. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within the Route that has been given precedence, + matching precedence MUST be granted to the first matching rule meeting + the above criteria. + items: + description: |- + GRPCRouteMatch defines the predicate used to match requests to a given + action. Multiple match types are ANDed together, i.e. the match will + evaluate to true only if all conditions are satisfied. + + For example, the match below will match a gRPC request only if its service + is `foo` AND it contains the `version: v1` header: + + ``` + matches: + - method: + type: Exact + service: "foo" + headers: + - name: "version" + value "v1" + + ``` + properties: + headers: + description: |- + Headers specifies gRPC request header matchers. Multiple match values are + ANDed together, meaning, a request MUST match all the specified headers + to select the route. + items: + description: |- + GRPCHeaderMatch describes how to select a gRPC route by matching gRPC request + headers. + properties: + name: + description: |- + Name is the name of the gRPC Header to be matched. + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: Type specifies how to match against + the value of the header. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of the gRPC Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies a gRPC request service/method matcher. If this field is + not specified, all services and methods will match. + properties: + method: + description: |- + Value of the method to match against. If left empty or omitted, will + match all services. + + At least one of Service and Method MUST be a non-empty string. + maxLength: 1024 + type: string + service: + description: |- + Value of the service to match against. If left empty or omitted, will + match any service. + + At least one of Service and Method MUST be a non-empty string. + maxLength: 1024 + type: string + type: + default: Exact + description: |- + Type specifies how to match against the service and/or method. + Support: Core (Exact with service and method specified) + + Support: Implementation-specific (Exact with method specified but no service specified) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - RegularExpression + type: string + type: object + x-kubernetes-validations: + - message: One or both of 'service' or 'method' must be + specified + rule: 'has(self.type) ? has(self.service) || has(self.method) + : true' + - message: service must only contain valid characters + (matching ^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$) + rule: '(!has(self.type) || self.type == ''Exact'') && + has(self.service) ? self.service.matches(r"""^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$"""): + true' + - message: method must only contain valid characters (matching + ^[A-Za-z_][A-Za-z_0-9]*$) + rule: '(!has(self.type) || self.type == ''Exact'') && + has(self.method) ? self.method.matches(r"""^[A-Za-z_][A-Za-z_0-9]*$"""): + true' + type: object + maxItems: 8 + type: array + type: object + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() + : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() + : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() + : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() + : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() + : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() + : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() + : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() + : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() + : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() + : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() + : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() + : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() + : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() + : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() + : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() + : 0) : 0) <= 128' + type: object + status: + description: Status defines the current state of GRPCRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +# +# config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: httproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: HTTPRoute + listKind: HTTPRouteList + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''')) : true))' + - message: sectionName must be unique when parentRefs includes 2 or + more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''')) : true))' + - message: sectionName must be unique when parentRefs includes 2 or + more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +# +# config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: referencegrants.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: ReferenceGrant + listKind: ReferenceGrantList + plural: referencegrants + shortNames: + - refgrant + singular: referencegrant + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ReferenceGrant identifies kinds of resources in other namespaces that are + trusted to reference the specified kinds of resources in the same namespace + as the policy. + + Each ReferenceGrant can be used to represent a unique trust relationship. + Additional Reference Grants can be used to add to the set of trusted + sources of inbound references for the namespace they are defined within. + + All cross-namespace references in Gateway API (with the exception of cross-namespace + Gateway-route attachment) require a ReferenceGrant. + + ReferenceGrant is a form of runtime verification allowing users to assert + which cross-namespace object references are permitted. Implementations that + support ReferenceGrant MUST NOT permit cross-namespace references which have + no grant, and MUST respond to the removal of a grant by revoking the access + that the grant allowed. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of ReferenceGrant. + properties: + from: + description: |- + From describes the trusted namespaces and kinds that can reference the + resources described in "To". Each entry in this list MUST be considered + to be an additional place that references can be valid from, or to put + this another way, entries MUST be combined using OR. + + Support: Core + items: + description: ReferenceGrantFrom describes trusted namespaces and + kinds. + properties: + group: + description: |- + Group is the group of the referent. + When empty, the Kubernetes core API group is inferred. + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: |- + Kind is the kind of the referent. Although implementations may support + additional resources, the following types are part of the "Core" + support level for this field. + + When used to permit a SecretObjectReference: + + * Gateway + + When used to permit a BackendObjectReference: + + * GRPCRoute + * HTTPRoute + * TCPRoute + * TLSRoute + * UDPRoute + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - namespace + type: object + maxItems: 16 + minItems: 1 + type: array + to: + description: |- + To describes the resources that may be referenced by the resources + described in "From". Each entry in this list MUST be considered to be an + additional place that references can be valid to, or to put this another + way, entries MUST be combined using OR. + + Support: Core + items: + description: |- + ReferenceGrantTo describes what Kinds are allowed as targets of the + references. + properties: + group: + description: |- + Group is the group of the referent. + When empty, the Kubernetes core API group is inferred. + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: |- + Kind is the kind of the referent. Although implementations may support + additional resources, the following types are part of the "Core" + support level for this field: + + * Secret when used to permit a SecretObjectReference + * Service when used to permit a BackendObjectReference + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. When unspecified, this policy + refers to all resources of the specified Group and Kind in the local + namespace. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - from + - to + type: object + type: object + served: true + storage: true + subresources: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/traefik-crds/kustomization.yaml b/traefik-crds/kustomization.yaml index 3806a9de8..a615713e7 100644 --- a/traefik-crds/kustomization.yaml +++ b/traefik-crds/kustomization.yaml @@ -2,8 +2,8 @@ kind: Kustomization apiVersion: kustomize.config.k8s.io/v1beta1 resources: - # curl -o crds-files/gateway/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml - - crds-files/gateway/gateway-standard-install.yaml + # curl -o crds-files/gateway_api/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml + - crds-files/gateway_api/gateway-standard-install.yaml - crds-files/hub.traefik.io_accesscontrolpolicies.yaml - crds-files/hub.traefik.io_aiservices.yaml - crds-files/hub.traefik.io_apiaccesses.yaml diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json new file mode 100644 index 000000000..1fe1ef7d9 --- /dev/null +++ b/traefik-crds/values.schema.json @@ -0,0 +1,25 @@ +{ + "$id": "https://traefik.io/traefik-crds-helm-chart.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": true, + "description": "The Cloud Native Application Proxy", + "properties": { + "gateway_api": { + "type": [ + "boolean" + ] + }, + "hub": { + "type": [ + "boolean" + ] + }, + "traefik": { + "type": [ + "boolean" + ] + } + }, + "title": "Traefik CRDs Helm Chart", + "type": "object" +} diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index 6daca116a..c6ad93429 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,3 +1,3 @@ -traefik: false -gateway_api: false -hub: false +traefik: false # @schema type:[boolean] +gateway_api: false # @schema type:[boolean] +hub: false # @schema type:[boolean] diff --git a/.schema.yaml b/traefik/.schema.yaml similarity index 79% rename from .schema.yaml rename to traefik/.schema.yaml index 84bc794f5..c1d47dedd 100644 --- a/.schema.yaml +++ b/traefik/.schema.yaml @@ -1,10 +1,10 @@ # Required input: - - traefik/values.yaml + - values.yaml draft: 2020 indent: 4 -output: traefik/values.schema.json +output: values.schema.json schemaRoot: id: https://traefik.io/traefik-helm-chart.schema.json diff --git a/traefik/charts/traefik-crds-0.0.1.tgz b/traefik/charts/traefik-crds-0.0.1.tgz index 81b81708ab0708c9690920b0da69b75c9afef055..b27ef6d26118b4db53c5a9028986c769f37576b9 100644 GIT binary patch delta 110019 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

s(0?|9~kox82?-|cQ5 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 delta 109791 zcmc%QV{|4_xG(rP9b27_Z6_Tk9ox2T^NrK7ZQHhO+qR8&`rLD8%{^!4&Zk*x)_T6| zRkdn=s9k$k{r10}SD~v{pksLeA8s4$%?!T2&wBm}C(Ev)@dOeZWoAdu?-z|qHN|CW zm#)icTpS_7;(vrtc_7TivZmiQdf>bcL}0xsT{qI4q8>^~;@ypm`1!Sx66sz$#yX`B z`_{sfE!&GV-U*O25Rs6O_i>N9?y?}(*@vf9?$nN zikweqPVZUW#zaYK&F_)Dt_@4X>z%^c0AR1=n27Hm+ZZ=g@)I%!^v{n(?Y(P47HW+@ z-DReglWB(Wx854eRAbtQ<>(gU<5@|gt1uc=Dx(R3;0-m!+P^Mu+p4GdsLr;W$Ck>| zRpOJ{!ICS^w2hx}Uv@SC2WJa`!jnh-9v6O+V~ISwYx8We;YF#KZ;mH;T03FPaTMHW zhWOXg)?#ktq-N)`i8rmjP3cS==Uc$9PjgRi9^TAf*Vo30C*k**N%BY&lyY+7!zVP! zvPykqQW`4X1pMuIe;mu9v)f9(JKn;RsmvBIWY)Nz<2($&7+!AxlF4^xmHUd}JkJ_` zCfwX2x9jg`a?axVV)&2#AmsoX1A&Ng&(Y{AoMw#V9f++^bzuaL^TtE-*7?x6u8ZyZ z6hW9G<0r~DSy@`#9ia;YXLHjxT@wUST4i%Ut#nmszE{XuA>hAz@Kz`Y%)!IQL?*D?_?JF`^{|oJOQ*a*KKW7>$jAZ?}RP=N+IjoIq;g*7$3k6WDiKEum@| zEuO@h5=^-S?aSUNm?R0R{dxORgc^9#`&srea&k?w`O9=h8aR%gw*J+BUwC&SYjjdo zz6O2MuEMqe2LXm@wyXTBSq<^;PySt#{OI7iRx4rX?n?Idz?4*+vS=hTt zQLalg;{mkK?B~D(7HXf7>Q6yC?)oC^&TD~L;vx@0$zwq$igT=4oA@#@#i0cATRR!Q zflx)RK)ELAk(4&dHKFFY5g?%60m%P#xlj`G0<=@$BgRsuQaz5R6tuq@+X_E2R=s20 zdy7YR{*I03^F77T8cYy~{d;VO8T3PpsQnd>r1M74_t~3F27d zOo%D?Gj-yFQXI|N56?lq`CS2KTpw*ben2~bIvvs@umPCZ^5$P-E_!lP9snY;>cN}@ za2uLVIE(Dw@L*O+`_@YIZhJWFapNQApN)@@jDNt=8_%*(2+vv7zLNInKLzd94bO2c zZgHeXb-le2;I}*hf|pt9;p&_KUlV2!b9^1u`GF&H{9eyz|1nI$`5=ed4=0j{M?yzt zMwh~a!?zbCtAxvDzNf_w$#NRB>w^Hw9{rN}s*#zP&fSL3W2x9p)STJ)@w{LCqdY&a zfF>s-^_UoAr|E}(;v|{#S$XHUqibKBR4MzNn6WhC9MflT;-QW%R!C3zWiSkjDQ95F zoD?d<)PrtN%5w+WD-)?@5fQJiuZz*SxG|3I35T$b`X(M481!^}Isf(3PXX9Dp-PBP zyzHUYtq+=9R;}Zd!jU+`Lm|tXh_8d7G?l%UtoG}dsFT;EUw!*as$CvGL#>iQyTMIw z#qc+CHZxL|VeIYb?-O23nWCD;!R$$P;cLvzVSQv+8H%JXz;;H|*jHO-8WO&Ui zWYtr39vfBMtY?OyHvsm3~^AqjuA z`ets%oYs5c6vyzYh?Wg5Wk5TY<{A9;xRq0M%r}+bA&KYI{V*qM-fxl%X?BA#5hpY> zgJ>J$x_!sPNo1C!Ozbr!kNX`!=RPf{lf@*0R(?8$NW?l5j8pVYG3O#{u8_E&Ot#>5 zZ7$vRJM3)i3m0uHB|2W#ybmdyS_UbaANa{q+Uk-EO(`p#iHR4MU=IBY^iM)Cv>u=i zHM&~=k9mAAdES}GnA6ZWOPs34bvaNX{4=0@2`24aBHc3~^%}C%*z99cYvR_7HPc)& zmVso6s+_uvW)Odrpl9`iU+HV=;iO=ptvH1i=cOS=P(G|jO8CU|G8h`{#0G6EW`k|1ftl-&X}}DkQH(#*A*}Ps_(LL{Phl^0c2q~S^VwTSHv@>pxN4kv zkE1JPK%D(ihFC;fVb8k?P{qnR5=apAm@UlmRl~YbiqM@9?XVgPag-_(gOa87o&=jj zs9@WJUQiuUF3wlI=%2LNhfhynA))BQ_lbtTo7AeNXlXnIL!@u*C_AJ_#Km)@U0CTO~L9}?%7brOUpX|}NMe|i3X zdcN2=v!h9F&{7TPB$bS}Xq&RzRJ0@IEoodHxEoHT@A)^pQy2omE#d_ZIFc0y#2eLP z7ZQP!{^Qem`}o}UtIM5MF45_@!hT@Q!0;Y zIVGQMOExE;N%$=ast%Jf?r>k4(iAO*yT!fb_J4gb9_2jGbpak8 zM`7%h==9+L7bD%v_tUk*H?UMQx{pNSKrW4J^nerb(PJvJHUM#bx`}okV}Iei)Jo+u z{HjXpZ&)7!iYcsVCr441Bu43kEp$8oat7 z3FMPa8Fi9BP2u~{x+z>%E8goZ9r|sSY^Pnt+$A`_ytqHuW3e5(OdQ+c8N`V(jAs8GMhz062#1OeB5-}f=lJH)HZMTyh|y=FgQ$~QcAuQ%dg+j`#E}V z%Lqx+)R58`wHUU*`bzl=cZ`%$`$c%?G4^b;$1ka52DS%}&#{H65uTQq7|Vy^Uq?e>oJ~B|G^YeUT!Q+F6Vz$de;X1Q|<9wi{DGOj7q!nV80tG-#-LGLcDP z9lkjc&mYDYO?{zXA70zw+duw$C+dG#obvibZ?~(2T1+X&A#Q9##qZNRR#a^0friixzuDeq5=P29Vc3c~!6geE-{Mm$YLK-`K zT(=@DIya0St2>nzm}cCMkkARr>K{`p{->HZhM$Q`CHk@t`cS1x)IsBd++;@mCD!F( z8vzVGMMJ+8JC55PpguSq-b*;mO?h4*Att999I7U2@pB%CBeQY~l!`3j`-5YbhtVZv)#^zY5pKte4t1r;2lc+T ztRwROW?>3V;RN9b8IC3d01Kpt-(-+!j8w^rk%Tqb<0`Xie-yJ3jpu|&7%Pc3ZVB!t z51>djRi{2PiB)DL!_dYCr1&A7nbtgsdf@n=9MxfBJf0%#8o0g?nVqrA(;deS<9%UL z4QJUvjP#TApyr*|OKU*vxxHD7l3l7x4XtcT0PuO#oicljA@p9IhMn*$3v2@SVx_cQb1U-G`QDAg{o&;si;jTxoo9U1CbBz9tK;SVMYhlH8@vmb@$czS z$pnp-#BbqGgW2C1(%CH8endD4ZwSuN-5x01(XVz1&WJaJ6e_AtDlB4yDgLoRDYqsg9ev5ub-unj@%(U%|U`@S|zgUcz-7^#` zB$rQr7ezfCc>`o4S+7(KRq14_#TuFn9lcrUHJFx#-`nh-Je`f)q*e$aTVs2>6W_N0 z!|khd3USzXwtMFxOeJ+c>B1nq2v+G43|JqkH#gp$E&IzP{D}(F^(GBUZ8j_S%n%d+ znK+^1j36g4Gz(4SLEUVuA7n}eY63+z^yvN*V2LnodD+v;=a!4kP*nb9P>FK(F{euN z%R|AGEakIM{Bvy0ohu}KuNU{(R>tLmQ)}hp0$##svk&cN9$f^1R|S4c0MF0062LcL*5VJ?SbR^wG)XnqmhCXR6?~-_BiS~C(b*1@ zF8H2pPeHtS+Ygy_PA>d}G>xLaa^oKy3#0O_q&YFT zUx)FhOPFvsoTxOp6!bXT8=^w(eQ1F`n~?=Kk+<3+jbrM}*$(g*~n*`QejaezE5q3cIOqA^@FG3oZ_Ui zYvaj+;!Q-P(rJcKW#~Fa1KB(Q9^*1yPYt1pi;39FVoMuE`#BJYN2j-~MhPxfXqN8~ zjU-)b4^Txd2MHW<0f1&|Oeo~~RO@Rgn-Qk#5r zT@#xq*->#djFZq^rpCGNP90hjp<)Q#)|0!Y02zTRumSGYgL4+@;^hzk7uK3!g#jP- zW?|Qqokcf!Hahr4m&4z}dFO;_DFw7QrSE8zkq8q1oH|ZOjiO8km3c=zNkA1lHf@q| z1T~pgJQMSjNI$z>xKAh2X=I6Z6`P6Ns`g<-BCZ2<;O`b!G7=`$JTfo2*8W*ksQr80 z_=$pogOZdb_^Wk2lXHClFro`sZVu}jtHx@iXJQEeNwI&lxIx+KD9P4!qx-#W=bQQ3 z!0Yp142;-a`-aYbbY(Nt9zgY(vbUWxbH5QLSo&1Bh|wGzP%R?uTjGTF0a-KNfq(p) zT)~mOBz>ysn_=9T+G%uAio(0zFhyP47m4{5K08I0+I!T#@QwkfSD?_R9VAGk6ihn; zl$lJKY&drPJ1Rzg zG-vbnf7V)(Sj*A>YXSbt;bu$xtz?4#Q3Lm<&714z1snAY|JnCkA8$Jy^uMdGrHHkd z+yi4bn2)1KzI-RLyOjzeVHq<~NIioR7Y+Fb_`zkeAe%#YM8}XY2XFx0Slh28^REL$ zQNU~LgWCzHPIugTcbekX_5lhRfV@Kt#WlR>SQpVyihqFPg2;}4G1B97iG<=G*9wB1 z&b0n6t%@6T0y`z6%^hI>53nkH;CHZK)Yi%gP|Y6&DOfL^dkrxuj+}p8ILSGWECFLG zK^abfM=uebEn8)Z&AOSKC0dr9!5@0QA3+_qsgM@)@H3$G$;f%nM{0)*GrmpmJF#G4bAYa9{F`m)M(ax7;KV_yVe(7G}4Mx7!%R>K@sxqvJw zN1xDhASe@Xe81|Z8x&Z;d2cmtY91{{gk>NEc5y0J%_*j#8MUJZIo4_?z1y!+30^Ec zE-oClvM|AsW4o~J4H<|54i*herM;xD?S>0inNgGCc`QW5qofO?yIf53$2nF|c|Xfr zk&z~NTE;1LT6)|b537TemvjCe3$yeKPY*xR7__jI@nk00z-el_@UQ|DaCTWqBTossL0^OaLTpC zc}8jXva99gLwnWfjmc&RS9Bfo&o&T(v8QS-NzP%pqi=UW6WIqYlX23Zw#(kW%R z!-)e)#S6G=6#03mB?K?m>IefFrTdd!%Gg+wh7BIEw1F)Qz-pmrqh9#}2v_2zCAXBw zj?E}IyL&u)T$@VW{DlX6J3JHzCRI^%rl!*Ge6Hgj>yEF>H`QubM9e#9{K(gYkK39H zNtvWB`#ZYO#3r*p9{*3ToDrGmyx2KxCU${0+fNA>XWv*aPqr~uH%yrpYW2?kn6W1_ zW7pMqL)Y|xH!#C2c|jI7(ZDW8)}Oq}J)#A3zBFX?G|d}%bJ6O!P!)}#qQRW=#z;h! zRIN%6!0_uzds&P0>$w7^Jh8sVcIvNB!^~H$xCUO&UmWlAMry%TR|hdqHLXjxX0Kj3 zxu}_!cCxw`x;}sXZLTwR%(Z2f4nra8zM2%E10)&&a5)C7;8$fe14Z9_ps9F4Oil1F zq0+%8%Ne(zPi40^d0<3}D%8o|vPvb5b(D}r22OX~_es~|sit!&N+OD){^iUo-Ea=} zj>=Mu^jS5ZVzJFDqa41ZUY_)LE+HvkzR_CwlTcm<1ye(dia_q5fsh&d5{T7DF*b?0oUFAJ%nro z%SdZA#GO+6`GgwY8FIE?!(MOt6f;d}}n_Yiy7n0(=gisQ^0B>kh_$v@w^buj@*NTbgJsj^uqp3qWn z$XK3Q^?M;(!wC+d?uWl}G%xUT-@bj8uU<46vCnz2-~;xr0&q%nb?iVWc8v^s-ISX1 zat$3oL5zrLATrp4rndepS3o9|`FSn+V6ly+JUzDh>@n#rm*jZgKPEf}kEFEk-L}VD zu1x^9r52obEh+)=p+>v&J3iR^V0CfBEzg2T(j%QVZu*fX1T%vso5#RdG5sV-g${xTO%+=y?ttBGMDSfWs&HDZH>*@mzsduQhpxNlUR9)|m@zsP3Xwa} zuY;P$pIp}MO!r?Ac6qjI1ttVWOysv066@u=b;dQa(%3pe&LcXNAq8c8FyR(6>kZIr z%<;t0ykBoqxc|K(Jsq-Yc4u6fZSZU|h!+?Gxe=hX4*%xdH}F1K{3!}KM{oT%xTpAm$w1UE_yqt^m)k{@IPmo%8hwW?kkS5Xh%zDKjE_yku z0LzUb@=EY?m@z*&cZv#0(Pw5@>okUCbP)Ayh^(A3joC0WL+^^HhG4+&0_xa{+k|+L zCv)wap}9JqIl=0OG+~!|?re5eU(ufXD0tu#&btF*;1Zol z=Jlk~J0PHbOk%R?4;T(*!HnG}EUtz0QL}a{F3)vu7e5RIzgIm}c@*iXte;z7FrLqj z@+5j{q|tF+#_%o)8^XRf$;0=(NdrL8V@w?qu08Q(SLoq z*{ignoi%I+6kj~I1i|@im zrI#crSAN1Jgi|vsx6{LJZHLH)= zAQ~`z<$l;@e@pYnoZZ0^s-masCU$B!3%4?tZsFhr9wH90g@1cRXAK!lZJb=+4`X9- z-!xis?o3QNwo3xMiy>zkfGFEw25htZ~r8rzqvy3UdsmRSKSWXv7NUgr2Nee_pjH?w7)j)A$m<_q!g+awqKg zw|FpAdw6xX0WO%D#3784=MXY^>9AB2us)&cj9U`!0Jcyn*tD5{dzzj3NZ8@VQ|)}a5sGAMn`V~ zlCgBHzI`6n7@K_#0W3Rhv7`s?hp0gcbmFbn#irmQVX0_;`docI9b|R21a2<8nbWjS z2z%2G7k7MJET)R}5!_ceKVt$W zc4>$ry`#Q9LVfdh_flX{-6kA8U4s|lQ!4fO6 zTcZov7*i>N}w!k_nPcr>IIPG~s`{X7I!{=3wnVU*J*do_N%$Wz6yw$)A#S>a$hq1dcuEUiJO- zA0A&DnTNTt5V9Yb_6U$W|^ehS&k@scUY$f1^>I-l)0@LBo-0b2?|!o%2? z<)`WWHNq0VZ*iT(`>^eTxW{v<$L8vyP)$$*fCv98D9ndgQs|gE|M;T%#|cnVhC&MP zOhTr=e9VGQ%9qxbh~yjJz@A9tv9sU)LlIy|n&Aex6^2gudaK}LP~PnZLYJ?WWL~OS z4;^~@+9?4dic>@r&;5Z!Y;OXynk0i6QdgFDpZ5^R2*bxtVU-zNtOTDAYV7IvhHvAx}0t_VhlI?8m2v7 z=?|}l6E;J;5emC(2;il?;0>8ElU4>p)0XA6R1QGxm)pRqDQ*un4f`<2QC$-B26?&E z8W)qt(FTDK?$ykOi30Nvhe9P4?#ox|g3KzDxfd;@QhE#0Fkbtajh92?`R(HtRy{Pi za0Qx09$`g)B~Eggr!t!Vn-o~yF~v48dFfc`QIBD&NIsJq8K*}C0c^I>KimoA1BD^- z%cgd11fYe>Aos4(bnE{^2^_PlwBx%-Q^dqZy`f|=XxFuwkx z7(PoBBJ8-yqlg^t|LKTYTDyNJHBYD8MHf+oMu_WJ4#S`q+gB9P?$|b zDV~XqqyCZY{zNSBtPLtjp6<9wD6Nzn*sT@TIFW)7G0+J@s5nCU@oT=fK?v=8i`S1p z#3DtwtO$^X(!)PSUU4w zc7eoUHuKm}C`#N2pQ}onK-*=4N+sG*CvdkW_yf?LQb~n@qmL@8OjWKiekl24HP(Q5 ze{vAq)m*1^5F{FB)RRocoeaso$qx@QE51@G9rWIjrqZbA_ohkbfMUUQpbW1n%T6`< zC5|o<`c$YEre+1HO?!mz#~-mQgoy!t8X>VHo99q`Eg`WeAJxC?5&zl*rV#=cDqdAc z)_}NPM}iJvwI-PeNF2+|(^6-v29b=g{DLUGC3k~m2RO8lv&G!MvwO$zv>QV)--yKs zw7`2PL|UP#U+Pez*3YRtwbm`sJz;O)6VTX#(gdMte`?_~$M;N8Xg8+LZ;Xih?(Os` z`|kCRQE7!D$<;k&DAeCMMQOK8(P=kqasWF^g#kw|OqKc`<`1yRA3rs$>9jI5YvEa1 zQ{6)U0C^JcASVRo*KGdw-S-`*W}n?KE$g4jDQ+6IIxx7T+g)mHiTUmPi$Bg#j@C8a3^1L0nx4vjB1|pk|^l=tI~L_m8Xy>dMMqty+8bz~hnCBUp8Rk}ICod43C*g3MhKhR4VFbq7nwptV2qmGkh!(O zmVu^no84xAuT=FR(OqkLMAmdLht@Aa3BYz^g+nQQDn+1o7-=#=$W4~9Fav;wP@O^T zI&`E?s3KqP!5eYkv%_1}LM()Se{A?`BNrIEG2XKtkORDb^88Ibkj>bgEne^ zto+R8k!?wl-_js?mozI>h8|Y_T94|y-}6%h66Y$+fm%<$K!`ueUZ|Ba3eVzy3WlLF zrED@RO^$gr8{!tf!~m{)B?X~=r^aeMN*Ah_$~2i7|m-CoG9 z?(C8-Ui`_M73BYXJ)B~VydQc$XSxlvgkLPzyZj?j(M$L%42)>Wep z{QNMiZGDYxzdB7$DbKf{gYOmI{$c0Abd8zCQz~&-0M=6^0|=bM4qVeNL=tuu(3T8v zle2nKI2#i&)Bu!ttF3JvghKFvRAFf4)u3H>ogF@Y9VLZLx;~r-jewZZ>U=ydL(Wu{cZ=Zyh(%-+;3^4QxApwR^inf59I2&&1;9 zZu#g;;;2y(fi&~)qst}PS4!R)N8at0YJL3AIzP`(wR{(os*u3G@Pas zC(&P8sR@jRCJMR|E=>+@xANCk+3wX&wC>yau)e3Kggx5s%Ai=t@Nq{oEuhrkp&X7x zV})5V?AtlGX4wM~{DeaI@g_6%^f>$qJ@BwhuAgU@$hW!ILOyIqG{|~ytx8p^uoJ|; zvof*22LN5e|FKZ^pm?KCMX>+pM#{&?m{V>TZ$Hk-+p@~b@A%_Iqh-gcPrvj`yBuHdfC9?H8ax-Bbf@hOHJ+pmG`%OOLSaSBKrUtb4ubf??=7e0Vnzj8tZK0X-rI0rO8F(jn-K|BV zKGOdq2;>9)Hz44g>{zC8wEq7U2{gDm{RasI%>Q>10J#7EO9BA2|BD1zkrJR_i7}?o z=g;59|{`}JnG+>v6Qq7hnVduc=9wrG~%={<_jFqil7C0tqe(psT zEQ9z*w+iZMk^mxEImn%4I37XO*Q*6(D;)psT?3mMUgiIpz()gu5;!RGj5X4>`D2|_ z*mutu(c4i<1EF#PD72mC!6wuPZbG{XG3ZXimdZa8z*;%dd#uV?1@P!!_CEDJ8NWaG z09OdUU+=EBzZ3YQfcKw=_;(Ol9Ui6k*U%NS2owa$PlT|JP0dI$t;8UrWR?1Or6Hm~ z7+LRhMa>&ss{+Rq*A&eYDdpc|XpT;-yxDwNd>uFm83hOYIhnuCdg`Bou+SEcR1p@1 zY*MoUOQ)*hy^A&#TC1{h=zme`Ce!?c^gD+mH*{koZD&OB8sWe5{=gpWYg7L1O%}{s zjRZ@QddE4|X0rtT7d4MA&+Xi&$Y-!tyKZE8!*kDg*-vjd$@t(r@!f6{Lws$)SBel8 zfI`{oU0ZN8VDsp+LzZ&o#sS=z$_MuaFldwh7J5x!)X6C0SIh{d=&AFUe0K2>+0nOm zewedLUCa3WK#wt%M5>tEiUMK}NJCz2Bzx7A*E^%4~MNpJ44*L1wYk%M5gAqL=k$byq#juxXA z#9j&rnlQCwmrwl5NrY~FQi64I*aZ35Jx!4?=7I>8DItr%XFANaats=4Kgysj0oC`8 zsWSN+N8ejSa4B5+PFd!wJ0pJC8g|*wEo%Ts*$Ur{+CRFo+5v0}C))BAC^xMEtef6~>==FIEa zmrN$3{x2&)CwlRTMi}l>F*C?v{iWT4_lT0CORT;2&Z!?89MeQuEqD14iTVCwj<(V_ zu`{2)CM{6r>z%+PVi!~FtG4}FSa$X_Iy0kg>}iK(>4WzIQv-N_KNc@@~U$$h-Wey2Ye8K*z_m3iuU`gvDI z+gSyjx68)~@59M+D;#E!QM6_Pi{_olsZA8^*8ZgoFyM@{R|1frez42M@P9NSpmn>Y z#|qRR*3g=rnmFv>Y*aEqyeuj)FFlgxh0CUV7zW{ddM8u6F`>MmMsXiqWgTQ;3 zLeV4dL|Y3!&(eS4ZBQy;620{9Y-VZM(T9*( zjECpkMBS@3vvlylL^2rU`N4ws(r()DYLgiaI~Y6BRJ^ajH^*(Vr2erCv{@xcd>{G33AzY14f7A2|Yed3-I8TATd##45A|weGL~ z3=m+F1tN=asWc5l*D#N-X=3{HJo%l+i^i{lzjXS@$&z2$_)0yn-4$Xt{h1OX#rU0M zG_Rb~&U|!(?a=uf^%W;WDOP11N395x0Gt!IVWsK0DBfD3$XJe9w75+iuzD<07xMzj zCN4~vz7D?)iG0nsN2XQ(5=3*dHcqxC<>=w;{P|d)o)@^Smd3RTG`#7dP7gpi z!@aKHs5Il|k#0QqTGh zf0K1eqWykafO%)1`>{$6_;|L*H=N5xctLhTMB*(r&lz1!^%!V;-HkNdwEi_O6v3?v zvI?G>2$^ArpK0KUzClqS$k?BBrsfxCs1JwdI1eozim6n<0CU%S*xR(8{@H*UUQAk3 zk7Jk=^7fr6($i$CF?Aw6E&@q@+dP=Nr7zeF_0Scpjc8B%WzAIs@E{f$Cv3AT(Q+L) zMXWcbQ)6~yrbpi{7FhH?m~aJ9G)O~L1WdtMLx^w&f@ zhQ0f9juQ|t7#8Q>bQ7k=0A@Uck!ze!HG5)PdafRcn~l*(QY}C1%C%p%J6xHgRB(f=QvIhjWBHuT;?WtcH1?#S66!sO z7KA$Vy)vi$+urF}nqSJ2^v?u{-n+(0-fKfOr0 zI>-+Jhn#p?nnyo$Iam^YH`TvVZ9Yit9z+dpRbiHDjH?KTkfEiY>p5aTXPBFo?VN9Q z(TMHg%CbLu?@3_JyVWGGNpilpY~JwOS^3SN z`A4H})5?1<027AxrB2FOW#eB+G;cU8TC#;*t1*p|YyDLv3dDjK+%eGKv9m-;Jl6KzZ0GTZ#pv6>b?X6u*sq9HTrEeaYM`X zO=XZ1jDZmzZj_HRLO6Q0@T6H=A=tD8*3oBa-}pud$={?yydk(RiY0Hu-Aguuea!Zj z9Rpya%Rz@L%-5-TZmI6IpENk0wV&+A__RIAbI=on3rNWTCUE3rL9u)S6YE@w(e6!K z?0P#uV|wT%T$L#C$DaxcBAgI{ITLnRnzKKg8^b}YxjP#mh_N>D5Kksx^*l_cDO@L8 zxUlW0l)xE@ivvRI?mZ7jyTC=0Dt3wqr?PY&^6p(w=Xccck|$@f+&$NRP!-eaC!&hcwgMP4zuP^#f#GAGf9IBnDVfsZdj> z26M-Jj*uTJ2DTW>0?Rk6r_nH2$s!J=@5av2ek-}rp-qmfZ=SQU*a*6(ta%!Xm$M)X zKf1OcdP3%$V;!NdYzk&9mpJy5bfl2-FhX5HTz?Y%br5Sn_ScMA-$ixP)>;O!TuXEX zVCtvF+k)V?M6_8$_Tf)6Hj~&5)Iv!y`keOk;Eg^B47U?(a=|Lwlr4l#DI$$tgo=B- zh@|;47E8^H-;5nNd%-MavE|n|i%PoaOE1-IjnWVxQa&+&{lviQJ@%IK6TWHm4Tcqh zxa#{CG$JZRqMdzJVsiq^sahL8`#Q);IMcrXeNR|2-~y0}_zFIKF;-Equ~R^r)uz3< z1rDxIJ2v}81(&IKo(mgSPM1C0-O=f)J9Zo5G(oGO)AD!y2JW4iT%FM449e6!Q6&b& zbHhqvO-^=t`#2mk7i;WlJPI(0^E5K1r|0UX{MbIy%y>JTHmX!!px|o(j;CsdL7mK)Zv#^8z0GBAq{KY*uye5S|89q*0Cy<20hWX7Mjh z%n4~hE%MI;j}wl>;X zW}da4HRLZaxvTARmPVIn@mA_*xSIa}Ln3S&az!&=^p~F;*~qtF2&-9tyiWWq*sj`G zP^$y&M2x$Dhs$SxX)Vsu%UKxXoUu-CF(&9(tn@kCv`5|&jEkQdVm{&TXfGwj@{dUuWcI5ZjJ{kf1IU1bKRy7(1_xy95*8Lk!jOI0;J5I$uxTBT~^ z##?vzWHuKCW@z^S7@UI+kxL^F#UHkfHRN8Qm8Ljq%%id$c|!c)V-V^&#C;ic-~Ar? z+MiJ?u%9U8H|)mu$xE-M_8MW@`shVR@D|VxWEjvQU$cTxc;9#)};UC(NW( z@?T!m%nnaaUoHI1V|1GkK`|*W>$-nSTY}1jZxE5h6d!*6;X2|S`VpBrf9)41(>0vbwkbWlxdi*>5e~o=l^iQ28g;i6XUk z9VD=X9mSv>K(B*ydT%w%oKE4ZvTGVuELxWb*W}zPkXaN)?_jgO(bT-GK;y+bPbsZL z@M_f3cb5s}&*r&p_vnM-Nw&Gl3AYS~a9(ZZfR@NX!-$A4((4BykfY0(Nci2?(FX_Q z_p;l;8?iZz`Udbr@{EQ5@-(GXtb3s4@bt#kh;}gqjPal*Wd57K0v1x!d>0qC&ae~@ zet)dp2x4rvLq|cSvov;@+0Xba=M~>6g1`p%*Z7*e=v%g#z-iev1Z-xqej97~C;R8{ zyq8u54ufi590#g?&2df!-zyEo@mrAJ)GnK6T(Pdl5ApUlzm|t$njLy|Zh+aZYCeP) z&lSc2HvcGZnKPLrRc1}V(6m%5S7|N5<)!o^;|$QK9zr&t6r;coP+trYf0Kr~A@rND zCQZR)b*<{^d6iPVI(7I*VT6(BkkLo-pw`!8u|BoX&1KO zFl~Old?V#PyO*~*aqGj8O1bpI55(2#C`y0q8o0^nU8e>He)&J1C1`Ct+U=0u%{KAo zVzGw2aypXQMTv0*4Jx**miZRZGRvi8lD?p4PLx!j8xP)e}|F{aZ1k_#_Vs5G341ZXsA*q5gwa#id^Y!A&mT^-3o*ArBuZ6wL=vY-CZG8Gn4T{H~J3a!-!N^w%S6xx5U?=9HJ_H?ef35o01TIK6$O~&#C4Lh8&C_^&Dh^GfB{_qg z5?^5?sPnQb2TF~ZL)q39*DL{UmYH{p@_skP2QLbTuy5E|?fv0Ip|xJ4DJw{{RG&TJ z))L4>y%KzB0!GI@B7rBaj^HuQC-kPkezy07@;xdym^k2sMXbRqF+#iyC7pU#Xm_VZ zV{O`qs+l@Fjh*R%sBc$HTjbV<#&XG#gIxX*usl7!ZIIUo6Fcbid(_=!;xZb8ivKE# zOv6M{-ud@G}Mj+woHxG_5F9QAwNdQNw3 zKhAW}CJ_*a4*2&2tlB}HU>QPQ@YyeU*ofbC#dO>XMm)Y#X505`L7n2~^@c+gG;{~F zGVINt48)6<_vcBhaElkdBvq8|#zS7|{sQJ>{ifV4C14wUq$l1l*17=~n35n43h-|4B*3Uq5kY(A(( zIbltUE6ForO3f7s3^^y?R9|CU7OgXc+!$N(!;pz&pk9+_5kW9;4{Fe)O3N%CtxuL! z;t^y?fAG=OP$u|yFm9n#`DwSprgo}(0y(j39leGaHuXQcPQ3vzNK|l0(thvb1LiSLJ6y zwD0!cj|bdt#9Hv=f$gMbcd7Q<_etp4(v5CfF0LUJAv?SFXzuwr+)~z3TvMP!hdQ_E zRbW*Ez9Dn^+3i~Io#`)|LSs%k^P%`Clv)6YB#~TWbX zFd|ZB@>U5`VzQ+F2T`_^bJ6HRGzXsv?PLeUkQtIx$2Rnv`(jW;RB78rJg5%wY;J%KQ>Dve#VdBwa!4n_RA_4Y2P6B7t?l#A%+oX0 zW9{@TLo-+gGQ@NK+v8H=77&>O=1$n=!=H8fSLv)A!6>=OWv-#}!CZmuP@zt5qK>X3 z?qQ%@`^!Km?|+Zf5y$!E@sGF7R^1E4d6GjerRNnM8vB4cwGk6uJrvFHh(>^V5lQFz z#B_8A6_I_RV;c6XjyWSq0SYI(MhI7yd*Mn#)DR8WHIw0v=Rm9WovkHgdzg^VN(MxI znuDWfkqeyniJKcOl0t>CTzS&zQ!r_y{rNf3unC+8mk)*Y<w%Y080J%4h$$;I4?d z4EWx<@pgAGZ`Jkb=I4P2@t=V20UdFODpn!d*U)BbT2GxE_pP`O)Xt14i+Y`o0XhmU zbFOTyW-iTRn*xFzM@?0L+1ERJEfyTXMD^w8wfcIO`iJ@@JHHG^$kvU~v)d9uYn^LJ z8CT3?9~W#4#>YrE_kH-qOKVz;&Jd^gv9l(vhRXCPjfp0!0~2aJ|*yd`H_ z$7X7lHAai!(KeE5WSaqqjbo_|@KcN&k?{Wy%FZb`kS_}J@kBGRZCjH}Y}>YNcP2I` zp4hf++cqb*v-$7C)^63-R_#+)-@4Tg-E~jj@0{;& z@UQdN+8UScmJ#4vE{3Ic+!BS){0pOfptpcqy|b}%u#(2Ip;bMJ6g~7c#0E21TNOt1 zHeESv7_3b&nPUY-B>Inc28(|q)NOoG7?v?O>5C0Zok&%#9y(Ve-G3a_~3GHj3)G&=SJ*lsT!Om~>GP@Xdu;Hj3Ii&t)=Ak8O zucrEKg5q4Ov)<;sML@O{B)V?{p_#Vy(W(CYJK`}DUE}1cN^!&q=VGxtir7NGB2>+V zkloyPQBkd!qJs%B}LSDjGo%f8=4Fl747_+;+I ztgF^WXfD|A@ujSePKQ_EKqQ{0#Lc=Np5&o!qTq>z3=&aqFk5g~7Q;cd#b|7AdJZcR!&VJab z(q3Jrv`b7xkL<$~T43hjBh)9g+GR(xu0*P+9(fxH6w;!Mq*^3clv4tmBOSqfLH}4k zkSBk>(YzfcQ0zZFJ=LMn#oX4dgdj)?c|YkthJN0mSbWAVxj8#Kvj(qLSKg}XTT+j!5Y6PSX>+8-vjwCFzYwdLT*k#fDa6BB1w;1_?TDUoG3cB#Cb@d( zSQ;B{URa$DFqOpyX9FNrbIrGVc0;%2Oi5eyAcWSWD;To9?clYJcC(N$n0~7eF_?a{ z5Cps7c&F)e{jI==ErlR@=zOQ=mmmV{CtW++6%B|=cOf6>2}a;Iw1Yrehz1P8>bMmX zbJ^MG^kUfey$*|Mk>mC-INvmJe8$ynUL{>Us{<&wkD5>qY`KJl3S@v2BK<_%cSUe- zoj4t9iFuC*8fNb`Wb@*)xXe;qh4uG`%CDZZQSjX>jy65?t{ewN4C$6gn0nM2+~Unz z)JherG+XQqYem_%w~bRLcmj-2REn~D7@2q!6sdJv4dpz;)PXVF=7Txui$L4B6kdk_ zyC}QWiUP(+PYfuqFN0dxMgr9(Ku-OsIWD6%49i zk6(f08eUKOv2Y-Qtvv?z1j+s?I4uxN8)?MP=vqN~4Y-p4=x?ASQ8<_`8CFjQ#K5MU zshJJ~t9gH|-0q!ZI%BDQyAsJ+m0tYl8$&s}2ER*|3pCgc^%()1%rH+xa+ze{H26UH zSP3!d!+=tJogsZsxFN;!_w2Hp#x4sPj@hkx|7Lp4)bqgtB%5=ee?cAhW-fRMliXQT zTH6@+xlrAV_nH9R23;m0&Y#X(QG7w7%kc&yrJv;xJ87&EyW@0PW^Gda zdu&(=#?m(&=QpGozdxHWY2;|N1Bf6)aC0@@2GZ}JF1|n|{#?|_H(R#2R(CHU=|=vK z%g*-?hAp3SbK}GU=2PY=GKZWmr@p+#S5$8gqks=HZW|5H6ghMkWlQhRw9Mr*mqwVG z>HZ}EBSX&wg+wl~s8#y2>?axE>%r#p@OsPO#nsN33p+tSXyU2NhEPaH9zOP|T<>1# ztsvNE)Cj2Qx;0SOdbSWdK#pPTjhL#sb;`Y$>K<5lmz7w_kj7a|mljX?UQ-q#g}y6; z(yyPP3`v$*X27V7OclL`UkfeH-8D&(SZK+*hOf9<6pEZk0fu=`e_-U-!?)}8P<{&U z#GMJHEVfBskyDi%e8jcHBfCvytwlQFvvcslkfN`11HDd5t0mvU3;#jhTR_?%Ofw%GL%ORWh;birq5xzc5Izu0V zpN>+aU^=sQU=j>M7JOxlc%a4YYe*#p1Na)%)NFhlsc!YNX=b%X8-@9>W1?!9^BHxV z0JNQyzYHtMnNosa4LNYZ%A{^S!KO(jSAvWZEHsbxS!ID-WuzO|EC{EgS!s@6G=|mE z?zylQD5>LVxjSam5m!OTXKb~Tu#oIIEk`8b5N_c+hW_65L+`r1oplxDuR-aq%i2Ti zB50|R;F5a-s~~99A34*-*3J^OwHZ(FWQk{izlQqZdMu*ckv+f+JN8tX5gW`Dp#ccT z3?bs+mjf*#ybrmwO0UK6M5!ioAvCZlyKKDw+b9u;w+6W{lrBPeD}xYMQf!dq8?xyM zvvC1(7h>sQnxnA9Gc@QJy1svtK0i76IS6&tQ<*8u@J_+lp2_X(083Re{X15tbIsvP z?I6Ro#X}~44K6S&?(h-iS0M@2_&p^*6V-5#qjRL+dBs4JNyq2HhP0Ai0ZM+v83%ELzwcsp7hCama=^x^W1K2EhJ1DI$ueN88!M6o zd3OVu-vW1H+D%L>X{K%8r|CSC!PTXs55_QjoP?gB^|D8)Z@sm&FvSjuGNU&I+ujb_ z%IZpSNps3V@(O(GlD-C@F}s^QGy3q*onoeE_uD*Qqv$Y%)t=v<>xw=KZHw9akPWHz zziK_z&Kj87%Zh>GXusvwXW;o1!~<-x9o16j;^ThOVHwwV8L>FNMKdL`6^z#A{~ajT zX^B;H6*a%#HYLH6_x8)_Jm)y|*4*fI_ZeHU6n- zyaLU>dyMl`m76^CRbWASz7(5n3}{-B&&Uea>Qj%T89un{x=MRmvGaYklZ%$+1^6=F zA449qIsxyOxzD$&mdkr^sVg!FxJ z69R?^El2v-ooT~aeah~iyvKq80}>=>mIX9z4HbdLevQe5JToInzI;AqA$Ok7*SB^vUKJF>S`+q;?f`&{?$D?Hpb1Uv}hV$?m)OjaFq}w2MC-B@qEQB8dSw2iu~Y%?dB0 zJyDMKdARG8hf@f)sI)Q1qF6W0A6)d|)>|>B%b`m~TyKg;iH~c3b|$Qt5NcthN;0B7 zp^1s&`@dUcN$={Mm6B2*Z%0nU8Qo=Y0o53g*trj)szPDjo(d3T!kHEm>^+97SxPS? zA;Qt*^*dNTcYB7$2hQse86Pv$&+Nf;TSm*p{sg%Mv&(w1g0DS$( ziz6->JK=1xG>l!S!y+r<8n`$OyEllaYq^`^KKWh!J-#G;5@|d}WPu5tHtqx^+U0{Y ztCVTJPrQegh`L&09M0PqBvNWP6Aep#ymtTCDx6RtBt#*xOZ5y_lzN=CA60g09=Urd z><;SXJ}P=n8wGNc6S65O;((PYV5}DO##JHT6E@5_&1STD-mn|fT3GH>*$UITDk8?z zVG_Zi;W7~JqOC$3k0iY|XPYj2`QXZOUNR0c)J;Au5vWUI7S(>amEzd$Kz`haF|g$K z%{o!yhxL9+<;4vn7(R zv=v9%35Nrys*x?N3T87S0Vwtii4b*QXv4OMQ~w|)l|4RwJI1_E!RsnB%abhH21~I1 zz7Iwa#7rd9@%v5OtNjc>@ig4t>{c-p9m!2i6&~rmeYnZR%~OFZqLQjd*EzT2!P5!; z+w$I;h%}PIOK0Z! zV_bEGS?m6lUjSp-j7y8Esv(`)| zh!bs%afk2){$3Wjeh}812=i@O@S{t=oF7Z-Lym0u)=<*rUrh@I}Y~l7HwI(6LYogd@l^?(RO*tWu2@tD! z4*dLh2=x)5)xW?W1n6aOu!sLS5akF>$_s(qHug2W4Hqozb(ARf2~pfSNiR(508zYM z=j#!rUyBo6(vl6jfN zo+!`0nMi3zBc`JCkWUy$JjrTRh#E>SL{NZ7L+`)1>DoUMQakgMm@G5fDGVj;SKPTp zeuZs_D?!FWDY9(Aclb}I2rDio#pt^+^#Vtnmw8bBcKNlHht3~y^echYD~_U~s zk=o>)%hRs%HF03FW{mxRbikZ`{AT>EAyEihcD1~laQ+a6xaS}SCAgLNqe}5T0k9t>dxNKacd@+ z#`Tfia^XIPm@=D;-@--?erRpHWMvFM3sw`h?4(_bVzpvQp0*87z>1|97SoqmhIz!n~{PQj}^gc@d5kY5((V=5Moe^F?d^YJT(ibR@bb0 z*Y|P#`S++O>6U6=N_k9IFQu(#js1o>!6#~uN_q7*4S5{<6tv#g8 zl&sP4yqYoY_J3BwSb-Dh|(gdgw4! zD?6MO4ViQtPRx)Z0n}vlIYq7$E;@qU)0me~7D=*zu?YDx9Jzl)Do(|^{={Nrb$cXA zrOfNe^|Sj51y_~yiMThYGH%UZB0-^Q!XwD^p({qYSK9N%u^LA0vDCi=5*N~rs^ia7 zNz%JQ(4!Sapj0yerIEVIs6GA)pJiHXU6I^tOq?3rzV4J_;dA1|qxWWBGcnC58hWF6 z5@cQ?Yh0GByVU2RTaCbNJ~d@m%N4mMO^m9iNQdTd66?mDQf2SUq0)RM)gKoU$uMwz z%vE!Bv1R=&51Vz;srD)J4R&*OM={WSZz(DC5f`?p*>E4A6ynHN=i!+Qin6<|Nd8SZ z`_;^sy808Zw9AB0~dciQ&CO;Gj!j^rOnmVC*tMQ@Nhj?|8-}G@4 z6nK}&Eq9p15{Cf^2e7|Mmi1lo&X&mmg#&szUAQf&_$CMaYh68;329+^MJ zMwS5=72nK&jlYG)ow+CRBUVs`LwC`-jOY$FqPeZH_LOP+G?J2)hdM&;IUCGM!Zt|I zAyHBg4s49}-_d3vQd;FRl^mZp+`jAQi5jPda%rKXr%+$h3=ym9kJ@U;zWS+e6br^s zYh@;rE5bK7rvDas#7ugL>n~Z@1za8VfGONMFg`up&Ws#v$zJ(<}*tcy`%Bf zavsQ2d(OTM-Ny9$ju*Y!}PF{Ic26CAgJ z6RSSm9(pWks&AD7kb;fQW-ERWeEN96C|oDd5s5^J!P7P9sPt3TMDlM1o!q9$q&?KN zw*ql6hv8xmk;A6;{=K41GY?UHrRtlQlS581tY(eLc$L6gS7G(Yb^}}`(kN!3$6tCg z?WLAYm;!WeHitfk6J9In#5pSWs%oj*2JhsH%)tm>_%gBpJB!)Pm6v+?jO&O_oE&IC z6uV0*O)h_eI>Su-Tw9COA;6BbwZzDEl+t zEhjNMNCXM$qX#)pu@_I%Fc^drpR;xP*NJ1~Vaw0v6)mvr3Exyr>^eGvTDLenle_c# zd$hmCB)oisIIdgC2GR!tJ%4`5?jte+IKDaezhoB>oBsp|pYXWyg}%@4*{8(owi?Gk zOUwP~MDyqvn_K-s4QE9BKs0e*NcaGl-tsxMyBqe&{q;eHzs%Bf|5;)W@;Je`nh5I6 zK_tzwS>MyQVgscB8B)D^CRn}M-@U2L{z1#`|JGf$67Ja)^DWJFLmisR#xI+b7T`_xlP;24)aVG3N7tSNPOg8iL|MOfjwxj8#Xobl<|_=845O zx?e3xpI}w{zc$)K%AR(pZK?j}rSpAehuXI}oS<@dKiLNj!HZd#J%NWC4R#ehi$d_J zz?10gAjF$yX2g%#7#bfOF}znDvqv7qQA-VWTjeDvYq}IkZU84<4CvAAVOhM({$S6L-EWJ5OZ#Cm%LGYw#SSZvxvQ_> zOgmfb-g5B%Di-zP>dnyrarI<5ARQX19ry;8#&aU|b*ibZxCd^#Ry zL#1BBP-Ia}RlKw}?7Z^*j{CtstKU6{f(~bbe;fypRE{<~c14f`&l6*^GGNLJSO2r= zUGxQC=2Gc)T?V2jew3BdAVQwSJI}$EUsQ083+#khl7a5ay*vuFW5q-TlX;2t$J!gRSl6B$cTdi?n?AHG@PNc}?#ny*-U7OgFr)R7=PQVY~lX*|esk&R`J6d8LE z!X(mqk>#yg8uR5V*9L;lk04^qM*lt~)#iL@dv}A^qyYM4)Af-MVne=-B+~Z%`OJ&e zwTYsPe3QJtpAoM%_TXkNr$agqLzPPU7Hc%J8?%{wFtf1Ce?zMQ#$nBunnc_8a7q$u z#g?{8Gm=CbBiKkbMiOT`!W`%=g%13{)&LuBo~Q85*RFkvcQUvJjBdQ8VLaKe(=LsZ z;n{1?!hjLcBz{qx8Hy=F&hyT#iGakY7_TMw(38gT0b1Smt2y;J1_jI);^B?s(x+%`|-qeGd8${C%Ex7Cq%wUsCbP*f)ihG zqx@jWmyR#+tC{%5-|t@wCZx<=k5hX9LCrym6VM)b1-{nNXKmGPCYXN~WIKxQ=G>0e z@Fzh{{j7PoY5X_$=+Rqa7LsJJ&XDEbV`XYj@p=zCq3%JuhkvJQh4Y>N`kT^YvLL0W z_~kmABy}@Gwoe3!e)io6`fg0k|p@a%kdt_?X%j~!V~c2*u$XN5-jhuzA4>rzPR_s(>=hz?~RDoi6%vF zx(e31-$@mL*Lvn4PZXCkE23)KN8ysg9(oSVQaX_##2qB2&Y9#o%KZ6HBlP^I5z0}E z!f$l;e_Vg}T-ViN&aX8|6F>*e&W!<-=!69RZLSSJTx7tkV3jCfTZK2lOxrPCd^n`6 z^qwjn{<1KcHIrZ^;n2?8IM!xC#9ioeo+uR+x7Zp!+>JXJ&oCFwr$KILRLt8BK0Bw7 zjS8hhF(Av1ZF7V#)&}L}Ts5Z=tfT_vMjIc$!!&1Ox?#DiH!%G{$v5aRDRT#?S!gg} z%V>tBT@YcyF^V-s7BI&J#}NBpiWKFH_)lnf4?&C2APNnWwid{-(pD__Y!m)kE_@^z zOWk?=UOJJvl}5Ar)s~Kl)aR!BI-Kj%xhFffheuU3p z`0e_7rk*of&VxgsuET$!D$564aRK$+sPz6ywf<965U4 z8ygoF0P!Qf@8KM0eUjCu- z+sKzZxMO1v-kF|g!wXT_;58;ZZuPMrTv<|&YVDO!3{yPfQ;HG3($%JjoFdn zpda&memD&}j38z>@eTqO44er~znNLE5nV@4I7e%`q+nFd z>ow?gwthSuXeBzn^RhGs{i3UeHyuNF)ZV|DSmICW^D=^>TQ^s5twPg^(pHRKFC;c} z{`I89sckTpKnod8m0{ShbsOx@rVPPLtke07z0NPCTH&d5RG7Ld6SZG=Y-!OFt>0L! z;yM&ABb3#Q-AWDA%HhPL?YBjW?#Hm^ocu-0A3n8QgKIaYq9OdosQ>uqZ>x^mbX9w3 z9dYF@fdW~<$p_UFZxA)<3v|&%Z-AgzPr$>+|KepT_ zM#C$elDjJbv@whcC(++Gh`+J5?<6{No65tFSdoP6Jw?Snm6`58xq?1Fk`sOpvVVh` zB6)z*uAtG(jX~!K&kVUR6Bx>mBg==5-Vg2rEkn@%tiWV>ty)hOL*rY;b4WJONiH;psl&==}g znTwo$=-XI{Vx(SY7^Bad@1rH#Y|Lo)?tByW0!14A0kN(y71IH)5mbW;c3OsNz?#>_ z!cjR3kn!+|XRBTIA^N$W{edzPHfpIDS1O@wVo!nZJokaNx$I)gqav47v%zY_-cpsx z)ML8qR7tp|VNHj_My+&MubR+}ot2j+TXNmaq@Tz8{76b1)g9y=t%xex7A1!S~`k^vzdO`if;a#ny9>`YqM#Vzd_RtX-uwKq)G}5_lI@6X5%q zobvQid5k5w2u37l-S{UK5O~>4pScHE@%S~+O&n5O%In+wEM~Vaf(V_$5dRm1aSuKX zcm|kt{I2WFUdi#(i0MH9AAMO~GzfXHDxQ%isdx>o?v$%Bv7nrcwbqW;h||rjf>QVg zamF{$2J3t!?_;4IxsKDfwR+ta4PWE(VMz^2l+_3ZB|v7a0HeEKPKXsBDfe=bZwWGL zNFQ)4$3PR$2&*P}T(DohyNg~&KLHC1(Em(mY0;y@k~}#(dA@v`6z0PtvGab-WI5s7 z+R87$Iahhx;xY3jm&@)!;qAg_S1>xYz|Jrgsd`mSM$ci41g~(*lPvlEXYh6p`QiwP zJ@(&Eb#qvHpY6oUQmhUXkzj-%Rhp>=M1ll5O5Nj`l;Vb3; zY;bs*SkQD}bfENnxmUG&{kozC6wMLvy@7l(On1P>1GjQ}30n_Q67g)li}A~Hd^URy z$L;^+PATMGbU3wUKf+T!y~qLW@}U89R#=>Ab5`s}yM}Cwcyhf<+7pfAbHDa*;7Q=) z8~pZBCPK~hfph3yHWLmW-d4~$k8@1t>RVQ{Uh^gEB>CUR!b;CymZ%o)*nBp)dzXyq z@z27nRd9qThg<$Dd6@}m6pl?ZSxUOUMZP_1A*wxDB(Q(`H}}@P-%Jl!rIF&KdY9ss zbyG@Zq?IZ1B?Vx(6ZcITD^f`)ARSaL7AcPn=cOqw?D4#*=_L$9<=7OaAVX(a| zs8SdHK)+#=IZ^Cf-q|+Tnxh13B7G9>*}+VvBpZONplOVTG24gly9U0OlYCd1b9BfKTJ7N_%PdD?(uuo;JjVEepk_=bPw58jCb@WqT zD&Y?wYJ#Z_Tq|&;;w9+-N6Ae{2YlBYSB-t*jkI{ZeK(xE!wW#hx)#A%S+8N4 zLFmx0xesxYCXdRU`{UJ$VcIN(mWhRSV(5v~ARKjy4scvm0VTH z9&THeL?gs>-QP%Z?5_G%!-exQob*i%9Ob=5o?4TqpT**4C1h`PvH4$K^&QC zDMTH5UKNtNl|__TXTnmToX3vlM@(2zxRlD~HBg%Fc!NHx{HZ?3$F2gM=R@TE|=z04W%mFX3YU-ybV#Ho>Fi{zi!@-kr4_5I|yWk zUuRU}=z2>2&_5G2hkNq9q|w1)*Brl#H~lNVyZx(&saIz>@-fan<-r&EvD?*I_LY!1 zIDAg~9Iw*!9n`UNeDIcWsuTQpTw=9rDv0qED*!$XCa68#*yp4^4nGq$Jgh!!HxS(3pa^@n*`3c{HoAF6$)xFiclZ6+RjJ0&k)2ANcL(RA#rF06 zSd^Y`i944vHXias{R!jq^df0%OhIt$v^5(fd3g3;GXew3VaaBt4lnI30P0>o?`ddD zeQyOLc+@JMBCH>13SHsG5m_o);Hl#FlLQc`uyy(`|0lv?z5~QUx7vOu>%YijJ5&m3nN;9!0;O zHzK35d2Ua9H|E zicS}G>V@&13)biC`}u?mBZFdNbFn3H|3yV~q^gvv^JwH%`P^*6D4f$ZN0;FcCLnXK zvamC2Z;H5LJin9KjfpGw5qQUst80xok*q6)qi%h(68jm`dwy?&(a#M z9c{Q1@5W5;eVf<2rPU#2GL?>6@=#T-Cm{0vj_onR8`sR-*ASCe&;9Ec@KD(qRm&DN zXScX;@>I45%(H@Sed4s5Zk5wKM&w$c-TOf{r2X{OXZP5Y5gK>{t{zJk8R`gR2lcQ% z**AYTUK>=bc834-rM1=^Vz`2LdCPWgL&TTOTliFLjaGVI=RBrMgcl6v5;rk zt0S6DELHIOAR;IQ9BFk+DX(A{lP0>2mMUGx|6FMJ6(C$iWSE3AIod_BQ@#K1Qcthb zQ%JOk#L>m${an~Rcp$4K?(1X0mkXu@#c5+`=VtKnCC#6DQcdihv5p=doN!A$PqcAQ zT&O!>)VimDz<&Sx0re4+;Gt8Mq8Qi;j15T$!EVDfGZ->fA1J5m z!79ZUnCLLN`C4O9D4EO>#?zfrJT#kE8Sk%~um-JVIm&iBQA)HulPA#X)cWUJPonA0 zSp4-oh$Z5mP9(_k=6#Mi!q}*x@AxK3pEZVG zYIE1NwisOm4DyAGTlsp$t9gAJ^?t>|(3#PR$~kx)H3D$%<=QD`U7$ABgET{|* zMZvbXdmj~7PHJ9>1M-sIw9k|>`)`{i+5OLxzC;(Wd>3@Z#4&}ZQ zp#AJKwx5i!Mxx+Jjg&>D|9oPjQEP-H-xpC#Mx)Wy86ijp**g(3if9O(ikcw3*G{8z ze)t9KXgQvX87=spXx3-?CLC(GaK1Ct*fSJ;7A#gi*)@&zTU|ehP=}NcR}LF*skAt; z?NB+`3G_HU(-#C?UIq_eA=tENOdRtczMJmnG2zxts;yJ~ose7eJ713PH<43V$&hnq+?P|BW@HBvK5ADagM8r9-#;R&h>N4(&cV-LMow2VU- zuLzNhKky*OOfN>haNs0=EGsvbhy1eD%V_?F)PEstJ}GUAVmgP-> zMQcjkwn{xqTwBnRf}%T1N4vc|QhO(He0qAYh@JW7#^z^kiud6} zh~3ZvXTj1ISZ2)ppy%JEKJa-H1%-ek=R!x$O{U@nd*hDq0UmJ;ZF| zPpxn;k9I6W*VFC_hV2?CuxvN*2udtj@x#sKEgiejymC1C7o?ZrLXK-10CZhDN zskQY&0_G4`1@`wFQ51vuAoHj~i$|=QArTc!r(l(f-(^!ZfFViaWNQ6{HxX3Y*^IZIj~DzS8mgZcHr^Oo z4Vje8awEp|IXo+l6pg(=Tq(rjJVswuvgdEE0itOSmqtn!tam)0H`~h;=~&Wckn~yj zVLM+UV}Ejx6N++>wPhwEEUGOPgAI+Z$(grSG2-5Hg96Cu&H@boBKMPYz#qG9blCdx zv{rB;xA`G3sp!G4@CqYEu5fVEf6}SEi+1!nnYKfg;j@ulUNx;36K$F=2IF-8-Q0*x zFC#9i^+-B?D;2HS#YK~{%PgS6=6e!MU7$Q*tu#z4o`5+b_I70dg%Wt+R&%1!^>%SO zAstNDBn&M5sD#)FOTkSXfFRh3!mbb~Q6aBsg?*L9h)C*SxWWP>*$VZ=eJ4|S_A5vc zWog4g$Xt+hNL`ae++EGTzrs3Cm#0#m8Tdj6-3f}9i^8?Lnu&+XZd)t_C9f9V-`~sC z$BSsg%gR$s25#!r$DcnxUm1KK?>Ks?GkMc9q5!&xKJD3P6R?2aXT*pRiPgoRquf6( z#xDo){*4#2=?~mj)CI5J=s0}c)}X#%{B=piV#{6sUUGY438VYi{R2PO<4sMVe~VFl zofp>^70#v}#4N2FaI=dO53%Uef51ixzRsah+nWgjhdz{sNL*u+`F) z7^U{sT1UfgSPk81IqCKe{-EEgXxDIZ1j}0B%NY<-4T4nVZBdd;8j{;$ZLbkxJ>H2s z!zFI3!$&LB5gLVWb_T+a@6N)p1SJ>-0`)Ev2+8Cil@P^>n|bQk2O582{ZzotkW75q zqRVE-OJ^z{f{2?0W;5szmuN^@cjAsH9xID-iirT=2$Lyr({(=e>NNZxh&@!&p5sPC< zI?`0EM-Tcn1q^JVa6zKvF`d-#^~A`TDR+QZ>KnzY3^sref?Y_k>lWKgtx+q#X|>(x zPq6BPU4`v$ZhYOfk!|&7DUW*I*uWFcek&ILX~uZX~6X4iX%MhN2SmPrsML~ zG>C9^F$!f8S71b<5%V%r6S;fmFEM3Y2~D3)Lz`H5BUrnT2kPnt3*j zbLLX$kC+^zY8}Ig*F2jxJr;Hq9wKw*g0_uiw)H8sl8ciEq|1FaG%Ej8B{q+W7`Kyc zx#1ysbQr!~0%yAwVrBNvz5m6X>s(S1*4r?Vi2nP^kFtz)5fRugpz0Onp3aD#lbKp` zrLC?{4<^gxhykgYWUui~q}58#a@cZEOiOj8*c&5Bv1re^b!~%3c>g@Du2&j^Ou~Ar zH@z<<3F=~2cG`#=qBKlJQB=l^9a4VT62lCQ|Hqjdg47*utaVE4=2%H>X-qdmC`OQY zSaHwdvM03;$S(Yz;jk}jkCT((Di`J{Nr@whuEQ4d0K7Satrp15xGcz-Zu9&P>}F9k zsjbIR%e`Id3M6{W1Fxh6zEGi$J@pr-wtC`PoRLAYjAGu884wmZyx1ACx4W1JF{uGk zyYW_=!hW7KpWIvO70f?YWQ6xN2tSDB3gVm;5i3>{Wk#L<=(r9FDM?+>mgECm67WXo z5FUf{KrNkTKy!XWKOGuDPcEP5bgmm;15c>htybSz&`D*2v5<0XV<-b#EG2U4sG7~? zf{|QuO!n*0W)I^7?b0!Ze~1$PWvy&WBt1)-OJyd4qXlOI`*1fPG{Uv1z>yM! zk_1BimOXWSVh_=*$!eUQ4jofAa85WD>lnmINO_F4Z9%D&D73{BxUSF$e}&i^sg@f& z4Ifio#RSt7z$HS#7#4BzN%Jv}R6?mm<3RIwrN-jWYkdF8%VY%#2c%6+O`7KNlmS@3vqer`tQMg5^If~-)lW%8S)wyK|Ja!inTY&wrd zAXkW=Za)(To4pZ8^4=Jr1M%;${BH6M)`YRc98xH@XweNemxiTuO4Hs&t3&a!l$E{r z$-MLYs_`CJq2>o+1XoR_xvSyGk)-Lxt}9^$FOMQT4I@)ta~)h5$pou(Lo>Be>h*%D zYz$HUXMZ|Nk-5qof^c(P41<9qqfiD$z|-W@PpIDBJe*JD7t4yT>fs zb7fNwtBhB!xhEyhTxW5rtJK)OkR-A+&d=EJ5;vw+%9O8u!$QT$u8j>mq`)Z|JjH}! zsPKbS)g8ZOfzKQ@4{X8g$H|`u@q&6g?1Jv7hF>yh(&_VZvZvWnH-}^!1TwSqRPhgD zG4*bi`R_Bt=jq56m(Jp^MS`A$-)DU(V;^LIJO0zWj#>Qk)Eo0IT$tAau2qJK8C|Mq zS2??VDVu#Et9=oRc`37bIlyFJz-Zr#_AV+&9{R_m0vV zk!J?KB#b+z^IZw~JU!a{Q(3snpJY)+;4XsKFhkQzPV9`NIpsl?W!_1{RSCpJ9_~DI zHKe`{|2Gft;=F&?) ztS}Nk5J^7b;LA?*0{oQ|_hs)hi$9u@@TLEF9YOhU>-<--(UaBdf(^i!;eMcf9VCL{ z=KvyV|QCcnPZqhX4KI`YN^v*{Cmhl+iy`-Vasc3+Y@9)HLX| zV|kItWiIP*CjDsQ1IYK7p2N)*Fs*vYpq)-AnYe+<0sTdiK>3Fh3QY)cNH%m8!z-}uHdJ; z9kw$PnbzD_O7aOe*S*_3;8ohgry>!@;%AJ=_?)|8ZR`LVC%O^to>ea~&4mTh$^5`_ zB-)0|s`+0nW0pNlQ*H<%1Mko2wRZv+mG33t2B+;L zIhGcbRuRLO{_mY^ok$e9_odkpBHS2{m=iy`fpIk;f~HIZmi_;R)eb}W(bN28LbEFm zv4MIlp@db2i530CXZlM3#8E;T_O=rIOJnnrhS3fd|2&mIS#4Vh4sektg&-`CgY?Z?H8?l9`&-MuOyYPP{f-{UBH1dmSBL3k zvxx6c)oPq{<;bcDR#?xYp1Hi^^3BzpnTK6usMCsWEucxD79pq!ACy4Qcq4%5zV3CV)x%W! z1TwP9hMbLFertUv!J@-4tcAP*9?u_v=L;(_k}}#vg=7!r2~^`kkzWa znKG?SU5;MotNsUT_Y_>&7q$UDPA8poY}>Zgu{yTxbnFw`w(XqQcG9tJ+n)TtZ>FZ^ zW@;{G-|T&J_RXoQZH&m2@o~XSR-Q@P6 z`5Y$0`~L=Q!}FL(t^f7v^`6Wi}I<2C9Bh^R(;h(e2mJ-_AR*gsc&n9dOnq zywcKQ@ov3`8SZ_i7umT)<0{zp8q=sGf>Jy|iuFI(XClAj%)Mhn=EkA81Y&`|15VjW zoRR+#J_DQCurjFtc$tfS)%7E}jB4<$isWO$R@F1q?ovrALNrZ*r7WL%bELW=QXYSU z(AyfcXL#jOSRC9R%A3PXWLvrVm&?K!Vjjer{NH1%g5;BVk8tIje!8u6+C9QJ961Orr1#m{U;1O1q| zHU&48T&fAzaL7>hDDYqguZn_W`Mb4&r)O%_>aWU`W^9P)!Ll641e75l*CuJtSZ;ij zEglc%gvNQuIrA^3SU|-vy&o!$vRwIvUV*+QKN)+q7zt4lTtJdsxxIBdlr~cj>f&cI z25E+?G+yHY^BF~T^qDu(Ug@0_e`ukZ6*B=O`W5khHsIu=X@6U8qV&Rv>(6Ns+BN)- zsu%>?HL&j%36S>HPIBp(1lRrIPo#H^lgplZ*~qf&YAy)49e$@3QRpex|9?cerr#=; zk88{rhL6I6RR#wtGd@LOAOoqy*lSpkC~(g~CYosuS)XY5wi=UI9_;VhPoG`CJ*((M zteV(iMl>0NlVFf@L9#!TFm&VA_;X!_d!`DT;6e@vj9gP;q_IzgHCdyJYX|ZPpRO1H zpc4{j5;&vO!n8=m^X{pSZ zzMB!FEmW#dMuwd}CnkoSE=hT6Q`CNXS0sRdrL9M6k+`ygmbU2fj`WjY8oyBBOc(iG z%+6PClG)W(va`sDz6a~@efr)(?(>+j^|_W%@I4G& z-t6mR=c9xn=ks1b!0XcUqX*dwrq};y${zAgZ8~4rAXjPS>%#Sy`zTw_J|Q}vm2ppTK_L#_D8#BUBT)_k)N~tE-<~?g8yTLebdZ5cDpH~ zpT4FnCjb@Y-{sq{TXfC3O~LsBYTPAQu~zS*mS58+mTD2fM8>*?Qh7v5_06LxH(MPz z{qsNVF4B*EXb3*zh^wL)Y8cIeD| zQjRe8lV9b7Zw^>K4`Mt!-NQCSKC7=3%?iT))_btO?xXouJHav-H*NF}BU%)UmTFj;0fm}^8=w_U66(KWr8aLA?=>_qa*q!cf ziz)oC*8OFh*!90!7aG73{&E+9136C8rVz|q-5ni4y!KSU&A$7P`m1~1{osRrTMG*w zs#k@0R5?L`(a?kp*MjInZS^>x_AkN1e7$?SSr&O~F zoq6`CKo^w)6Y?!1P9JazI&?6xfS5ibEDVTTTPVnk#dH8T)Ia@_(?WBj)uJ@1KARP7 zKU&g`CCG(2-Q|hA^4AhW*T|A0HnK9Vl8eT)cMT1vowC^%h|SW^E>ii9itj^yN5y|) zh_gryw)5dl#sjb{a*Q`skrq`<_MyHUgnkzrPK?2okz(8cANvpuK>f-j@T?pDi;Cmu z!tF3Mqab6qvMZ~qQ)h^$h8AHAG56T8Ry^0s&|eK5@&N&#lk!|S9?Rm_=6anor*;w zMzlE`;uhtD55ezFipq}#%R?@Jf}I1`nH-#Z8`e6z&;Rqq>DeKH31rgV)aJ^02xch?btvKhDhv}5pNGcJYw<$bv#9SiS162@VV4JAFEmOZSB?{I%#a-(oB(?rYf z54a&K9fjhFY|`mtzy4)m;lFC5clRiwyob1oUuxAfF36m5fsAcNIzCm-95DB`JeGTL zB?WFwgRt__W5(bLdg(pa3_a|jS!4INY=MkLN#*fxfh)WDWrC;VdcF&6i)~X)J2A9> zK=*`d14R$6G_3|hT>J2I35>b{6hPru2SAia)~7y8#|}uh;M}3@*NRa`+{M!At%xWT zRc_^HT(tQb;(E0J^&raLE>XCi_nU_d9l9N|Cnt zyDP^m@X#HY7AFn*Df)ZrV1efMVxmu|kZ#qr2WbPX$*dwL8|;t_E9ap!H3M(VF;(sf z{cjhd6~tntD56g2u2&Hk9jx-8XA+xf_kVAte%kRbF)MrQSK{*(L4lPspOgB2i;ct1RnUw!I-Lb`GQpl-)d zavTmPgK!=ylk=A$dSs#9_VWA~&3#NBh2hE}r23O-Sr%T%oh@r~^_~`694%m8&9li2 zQG8z{ZW}e~%Z0P@fQ{vkNGoC6V%nh)OdlNoO7BqLhg6JNK2EI_QqAr-s)f!%)_ zQ$cKNG{wI+5cWd{Ne;Taiv}YRFm|}l6Aw9XmccYEo3>q6&_DVUDU+KCXzku;Z0bh+ zUm(ARqGlFo$eQj%VH#{aL@b-$EgYaZ0Fut-cY_{D)Pn4INI{#tXeFSYgZJy`rR=~9 z_62zXxP)e^_UmpSB+(UcOf zLa}DaSh2N{E3zbf_U|^gXdCn9ZX3yy=gmvUt3Q%X=WJh71#~} zC0B{v-Lk~j9af$~Q<&+^P2!)JCD4OXsfymH*hzi^R59X7w{H8CZ^a_+AfVv_2cw${ zLxRL8Q&IEss>n@%5PZK_<1bXw7-8;P304x3P|^3Y-(VvmyeGn5Fv6EuDUl_hm$uB- zL0|CLwpBMBBOu4IMen755M272`ctNYrOw)y$`hbUclP2Z>Ya7f;AmBF-%kE&)VMpc zN)F^mg-IWm={V}7ATqKJwF{*e%@JtC!94nhZGWdgXgJgX^=u@x410lAb3Ptk{JM`} z|7euBk@Y~(#A(e!rx9sK{%cv~otWd7Zhvr~gUPqgqcx#P=uqO2YXcL)lii#O>tCzIVTLD`(` ze$cU=<}Cxjj@i+7ge{I0BYH*ZL zrPX}%-`jM*Wv0#oj7U-KjJQ&IQrvLzm+<)b3il;MUGwG%R0S=FK7&1EA#Hd#ZIK{W z&|(06;!&cu&yx=Law(DqdH%oTAjo2=_p!QAv{ay0@*F>*Do6Qr!C3N9Q5b4JU5@E7 zQZ-d~Ig=`^OpcK{oka`zE#6S=$VrG3=PrC+600~SnC886dM%Lj|BUps={fAOh95P| zV(8wO9vm-KK;~JjaqdX39)sttr?&%=T)H%s4+7V~u3OmUG3jvm64bP`86`WSMQ0&> z`gfL66f>Rwj=_s-4mQJRgPtnGyax3y1ooRtk;Q1;R)73r z={7Xj340OLhrd(xb__-kW1>?vb?d0nN@>VuR^th-X)KvSyn2bDJ5j05_7a&K819|Q zD7NxHsw&XFX0){_%l%cYvF-p?h+j2S*351f{#Jp^!506uYb`lfy9$><%FC|XYqw2d zD;+q&Zql63deLnawU^xF6ZBh-Zfm7CxHj?ADVx3LUx`ur#|>S@AI=p!{Eb}9@Mkdo zF4Wo$FxCSfN+>OLN(Nf8X0r{O{H^CcECYVa@ ze;5y^J>D#lE+!ybvOngcIBc%%T{47}dxI~imkVR<0uCwXWO zY3LVO;L8C~CPTI`*1x-5=|mhK5Pp2FOOlyg{!B#IE#;ONvo>hNtzSDvc)~6?4&uvL zy%!|d581nSO@{%>FC^6BdVQJ<^mF!&jjkT6egh5Nk5;W559e~#2i-k1FLE4L|08s@ z#{TDK2LL$z57!N;;CwOB8|=@9i<>k?kPq^28axU^^eNN*;rT+eCFR7N3y0-D3=){n zh%UxBAGp4l1m>3HvqRBfIiPeCysuEJb{+XhdCv+4N{x{eaj)9A0LEyWoosr=}Lci-g8 z$VCijFo|2B8W85N6lFw(i1AG#B|UPip#t)91mHtjqiXvhE+`pG5~oe5YcB3m^Lfw! zN;$WHq9=|9^Ms~;y}zpsA((Ld6gi$#e)?aVU?LE7Kwx>|`DpV}?bYG2*&kqe`Df}V<05;I; zQI?!c8l)_dww)v;-sFl@33#4k{U63ep-MD~j=Z%B^k-AL+ z-2ZXiHt??Kci@fl|5{z5`3uC;M`^|A?_XNIH0q5b{HJ(1%=-VwyKk!fQoHF_Sy%kN zedc^4-tO~?mJ;7>GtjHRoF}Je?AtGK+A7xc{Iq@0?1Ed~m5Gre-zy@Q?b}ndu5TgF zNvsRVYvH13phcp>E6Gj!IV3YcPM%AtlSWo618V0;H0w7)&e*5`7dZdy0~3~%zW=mZ zdXhD%0KUNzA66tGcSLX!FZ&~d&dk`j2o-N~#AG%G#ww%}W}V`yX}54VL6%r}vJm@Y zu~)gXnLoSMIKmsO-wilZ8CO)$oE1xp|1k?V@vYP?{mnvM5s3B{)iK{Itl+>RW(o9Lge`trbJ>m{#zY}a=#iEoLbFSKAL?sJl0AIL>`ibg%3(o zHu4>g&n7hud@SZ~wj;`iil%C$Sb}PPvFDE=u!$KuqcWMoor2J9&lwAIpuQve7L)J{ z>;NKjnC%G)y!4qf0q4lCrjw5m2Y~6bcYtO6QS)K=V=b=-oMaBKRY(3mz$PG@EskVh z?E6nmoZ}?A$$t`~JoRT|=;ISPlFr@W=TR+XwVE1&eTItieq3LvDIl@p_};3^1-b2K`y4 zC-zSc^xa9EnHlSMlUnQ%p``TBhis6nRp{<@O$LvnZ3Gu)8Jl{n)xN!Jk5Z_*=$jXj zVRO@%)m|Bo?5Q;ri^qQU7}LRaOhZTX&dKoJgk#LDJKviNLL-Y7A;ZvlXHNF><4i85 zPD-L!P#>@V`h4&o!R>g#0g0VwLbnK0Jl;`J2AocJw!;Q0%?MaO+H46j|30#*7F65E zE9cL@OwE%Zbzm&PkT^;1HB>S_6pjORyE;AcUh+qzx%CX3G4VoIdNnjiyh=rRnP`gN}sqXfEQ7zK$o{F^Dk^4y-umTLi#c1`qV~ahw z-b@wx$)TCJVKt~q0!T?DX)X)J-1zmW{7Y^5mQ>o$P^v`z;;AD~A0EvwMk2+o3yNbp zUZrAlzSW}GMTz8vwoOyBnk1FZI%%WMaBiBSI=DLgd@k4+@`b(t>4ikroZAeN3fQ*# z2*#i>20H=@x6DUYV!MQQPs6ZV8Cvlyt{h(Fb+73@5z%5O3Xq|wh1+ci4qV-sKv0<& z!*ZVtFY-vm7)CT!?KD~7Gb)>ryh$fgDh%Vh# z@Vmvd$)4^5<-LFO3rUw(g9>5`|v$deXGaVn~+nAI$~#n9fg?6bLc3VE&k zXqZ3i8ay8bApz4t;RJsXp%+}dNj_A#X7EOuO{?oaLscr(0~iG4m;&0RSl61#Ve&P# z=e#-%Nu`Oq7_T41s$SiD1N%92>w)=a>twZ7gSVo0nF_hQzjL85yyI(*=_+=)WCsv4 zvu9=mRAfH7<#xKi4vcf_CjENvLO;ON&cc(A3kIX|j{tdZ8q-V`#xPX=B&|F4J*VKy z0IQ))i%3u{*NhD&wlE#TO>bB$UM}NIGUOm8ncV8o!9O}yA+BPSuv0U>fxo+xaX@Hh zCJmW|f2^HMmZ@1><+vNx-2$RFDX0>Lx(6{YbRJJ!f*O9I z?u9w#asPJKX4GJKjJ4hLKXHHOU?J{+olHN*-mE^(fa~B7MmE~;t(hZS(hGQ)ZMLeV zAi$-?Gkb?=l^^QDCv*x5 zgQ|}6s~mov3Uv1la@J!<^aG?}b6dl1yOP1&g;Iaf=(^t*$lv6=ocDok$vQ7_#!p;% zrDUyv9nM0ElVYq|m~vbpG|vtCCVx{62EgN0*2Bgic^bNIc6qNR5wXtdPL~oKDXH=m z`U9h-?2o}kBN0rxm(ayihV2VX9VdL98xJRq>`OxSpyH}%X&J1PuJ`x<`Onz)QcXHo zk=xVblc$?yMt*n%XRGT-#^c`;hsBAQC)$_mR9em`iurZmR85HNe5yyfSc%5W8K7&S zNR$$8Pw;G`RM8T==;pm8@Xb9i>Tp$7&>@pmX=B-aP0K|C&{C7*er$#NiwV9{t+qLi zDN=FT7u72V3~k>=wdxsN02#$);L9zr-eW%te-Oc>*q0pEq%VYroeNx)VQ9Z3=boUB z*RhIL7?aBr&Epp z{?_~4^M13pQM_?fP9y2#ocx*_E_cm;ho_?nK5GAx8@h=TcK;Ex`NV#KfR(^^VD-qRe|C)TN`k9 zD^BvzdIX6egVt<7m4RrEcEYi4et-Ig62NC-K@}1bX9z)I5*lZOVXI{NZ}_w1O0JX= zKxb(Ho$@^ zPPPE*_2HXYllSr6F94Hd-3|f^1vwzw7QcI=y8v<2rCtZY4v6-0SuiL4W=w7ZiS51e zicRM?bZpyDuFTAog-w=!4hB@O`3SVdjZd+~P{I}(3vr`=4tBS-A3QlEP6ONMDFHoX zzdY4^98+R(fP|B+NW4;j<0+f^vm2-37dV5`QYz zGXFa(nUPVK<9@gj@46#5k2B|nJ#H*lnAsb#?0F6#iL>K&6*pPM@!`n4_2AQP?&Q}! zSz6uU4X2)Qtu0@Q6^s{)1?qg@05p}frEV!_G@Kq9JSK5D2%d|W$v&_6hcc$>@3sId z2mF1zR8sT1w67>bqJpIf6|0P8woA6iJPvh}EtlcuqGr+`ICBt4G|$Il=P$B@|v9o04NpsONy>b zPj1Whd<~gj#bSHSd%F#8)%tv|ka%{0N zljNxnU3M1lWI+jQbe04|IY@T%QRzAHNcUw|YWec*h&Gg5`Z>gLfZx8s!E#Y#2o#Wk z+Tmxj-}5=-7rLJ=f=(JR(naUsXT)JPtyb5tt}cjqWq7<3o=Hef!vmn_=`xgB=+T@1 zs!SUiz0Mx8UI6T>rJG7ow%;h~StFJo-8r&DpGoeYK_8ZQr71YQ9ga4 zD)MN8RM~9Txj#$-@80DPH)=!OQLec*Ug{N1HN?>bKQk6@e)5Xo2~cj(2Zqd< zKXfNn?C}3y9787Z;Q-)W~xlMUqIeZPQZ+KDOY$HKc&gk% zD(8Ihk8s8+H1#03{`N|ellJBHZ7HQ@Gj`@AR9ik zG&b$nn_S>@*=4CKpy66+M>(=;^eql$3q8yg8lCWX0@!tzRJ=mgf;uS`8cwAw*PG$O z9*aAFUwr(7ZD&SjylLT9K@v~qI_DZI`^E$7CJnx8IZSfCJc+0mZV6lr)f$qp$r65Q zP1Geq54+&^Gd&&)9~2WAB%XmCTpldg-5*;5UXO3ko^Q}00Nn5V!SF@vHc zk{-CoEvsH=coM_E`*E;7x7YkSG=}{4I^9BD#d@SH?>uX1owu2t)ta_c_Gw#1feJbC zuRoEV+^-=!IuBR236h9+k0#W^_QqPK4wP!P+A9Hy+EET=7_8HcR9z{3i@Qq1W~ld?fPsyYMfYRpq2j)WOnh}JCA(Zt-*f%}z}VKhBd zDmqZtld^YP{W^=C@UZH2FPlr3yni z5K}C8y^(kq|DduiUk@|p=cNJ7Irlg>RJYNb^Ci+Ai?fxd(+3gPyS-3L#G@z<<^uSM z>m?nau|Oz+Dr;U8fO?cHm2Tpv`POhu9@a}abI%tWxFK@oK8nnrVekzj({GEk^QD25 z4xuKepw6}Bt!4Jx=%K#HRN5+VJK0lrWJ4ZUb(9o~bRiHscU)?rvh#?pdbqJ`R2XpS zvEOqdX35n-k`dxF{(10FDLVKyZUQEpJ3*h!EN^=iQ#&ScJHN+bY!q(>iB0zzXh`MJ z@d+-ok~HaMe^N*mYsdFeb^G^Kl@+?^C8g8x9N5)zIibBK>eaTBaut|NrRDqKk0x&6 zo1l;&WWsMYQ{>R(9D6B96@xUBYZrwexk-!4*Sq>eN#EX#GsKfzIA`J#BKsNg|?3QJV{G96J$e!5a8j34s1=tc}0s##Cy zLuo_p8M)#Sqf)Wq=j3njUBKV4ieJa8(s*_}b-!X(iA=)eJl$lvUT??6^<2IWp$xmx zw=fWiDmmBZZ?2@4hb}@+Keeqzc$F^xR+Y0k-xc*nvEEuNpD!bEc$8#J`P*H@j6QL1 z6FjMYv=F_We`F?MNzA|Jy7xIbezujwIQHFZ6L*xzKXov$zT(MT=_PEfkpc+*cCcSf z!M_zLx)5!RQ7Hy-IckjJF0@sov=i*c+Rb>6q-(>`X)t#)+aWvvHVSa%>NfkY3;4%8 z$-dBIZavxSZ6;t`hsObW^I{Y&%HOkl)z%7vl{UU7l7M-9Vy7Bi&a|%X(!KXD6qH8j z*1Gl8z5Ka{1&`=paa> zIHo7^KbR^2_)%irZ||--G+r+Sg)%X}MI#cEPZTQ7E-o6%56Og^8BS=wHjcUr?#?Nq zE~SsssIW=qDa1L3yZdMOgP4Q4kB)KJM`1CKublK*CK@T-4t7(g-2v?WyyrN{(N>_4 zF|sgEXO-#n)r6;$VY)~wjf{S%PT6>q816n!w<+E4Fxa+P`!fsq5{~Q+f)T^Rdm(%T zWJ;Q-v>}X=x%t{ZAz3~(3nDYfgqHO}(l35#x}!@g=GHgQC1|NbNtzE|P|ZVvUHh5Ji3PS(Ol z)!+X%@hC#WAoxwsAHz&Je5|gpM?J^OqlO5w+v>fIc)=1r?Z<0UP#K$tCD?c^7YalS zpi5|lE}kkwfe!IG6RpII!NYy}q#sJ3%{7rWimc3EnG7K8egW*cxu< zw5kKi-mQr}Xz-)VO(duihI>!|qf%Q+Qq0Uq$=a0+R>`Q?Dp#xBr;VHvYN@srGogEC zACE@yXG8>(IKDkPix|!%yrV1b+o!}2@yq!_yQd&!dL$o}{*OPERL$>%B!B^xPM;!wL7 zA{k?Qi)kt$vG*Y1vs4s)JbOIHKdC|r_HNf z+n+k3r{Dk!+O->20XF+xsJ|QGu5{cd5Gb~LN%zbg`;A^f&uD3>gz!;jwI8(1@HRJ%aKkQCNMlv4mO1>w4?ITq?nL;$% ztthi#c7IP3y`-WT-;|DO?+jkNN$uc7p?0gE?Q+PO*)x`rv*8#MWn)+&^{fFGqhcZp zaqt*)00P`OyLd50lxsc{zLJBktd6h?iZTJJFv;?fCMfnX+oA$CdAluG2337;3&@kE zKs8wqa>Ni3T2;TEL)h{jYN-xiHd%qi;+FqU4F~9Ot$!#76wfYmS$+#O0UZ zleGJL8x>1Ry6Ha;gQk!w^#dJf6`!MEq-4L18YpHsp3xszta~G_Ss3rdmDrh~W(^&r zDItwHUbx3;&pVw{t2`E&xy?3Q7A*M35(t3up@>D?L(R($I(Bltdqh+cS$c}h7_~6? zpzBULC2&+(A3>_fp)D%9S)$g;1WlJeRvr2(YJ2g;utBTC3tJ0Q^i;9_fj>J|@YIBM zLbYYcS3LPTmueAVsij>?J@ zQFc`dGDwCFv*_~LqVz@4;aaGbKj3Pu&{2JH)9CD+j@}i@H4i`T=q<=WKn>*gXf8B* zP&!{^QoCbvW0O6~R5&sM^v|zsv4sFX$!@gB8-2(qoK3K4Iw$GYJ>Ox0Q$w497C!xB zng5P%ZAe7nCaScdp(v+mL=gsir>iI_Mh_A|s zdT%5l%fd8??eL)xtu|&j!|#W8C6t`XY9Y3v5rD6LX!lk;%H&>D0P|f_S%wbPR21On$rsO;EkQB&KDm=|)4QZ) z|J#L|a0$%cMG@T7<~QIzas+0gX6FWo_-t|j=qi$R&BbOJ9)nBR5XXmYfk=shet&Ax$%fBYRKPX-Oi zpNm`16CB2%r|oXj7RKca26_1o5PIkp-A|%DP70Ff(tu5-rh2e(qfPCR)Mp~g_z;Q) zt~ZyfNV}SWE<6uURzd>oGJj=?F8(9WXiq-k4h-g@)%csy%|@KoE12Qv*D|UL1uBnm z7b~J5nSecyiz0Z1taM_W-NX}b$ezv7?9;S<=(w+I^)6F{&WLtWhUEk-C5&1RL#+P? zgreh}x217aa3laiChWvkMCLy;R31E ze=H&+LfNfVI^6?Q1PS^=MK2&l{uVRm>>wPUU9YWLl7I*qL05T2#v{4)YL{A$xZIr4 zd$~Y*kWpVmJ=Ptrp8m+H(X3|m8fpkD6df0^#yToOne+++zs7wWYd`*;)91{@5~A|Z z^kF^2Oi6|9AwK7_9+x~LSfJ2vKOD0*$isMr=@kG^m@o&B9hb$9<~TAZ@t?Giq)BGT z8c}j=USt-tW42*=#JUwE8*}8wpi@D^9^xc=p||=C_Lk99*Xt|!vmB#JANFO-Uo1&#CZsP{wG z-v}>htjY|)nAQW#PL*-RtD~}wPx%kYKM$2VS=PL!y$fP2>PaBibj}2gqm$kvq`&b~ zVac8AYrn9oRD^Nt3+Vae`irEr;gqR6@kBvb*CA64aD3skR5?7+())!A{@RzXqWiNz>vW#L4dBGeqkE7NWE=GT9UO+MaOG=<96+i0hc zL^W~&B+;To=3*X~{RB|p?pyfQ(_{_*StHn)o~g5}^{1_{4^1rIm^8)EIf`qiUFeTl zUa!KNDDj?RW7z$Ue%EoP;6~8_NTDhurmx=56Rs zN5F{OES!ls79&&G0uq=rgd&AK?-z*8Vn(y|UyNn$yZ}DDq>ln}!NxwkVjQCh6vjS) z{LhbVzjvKWk1P9Yl@__Z4Ev#-n(HZOgptqBPctRz$D`rBX1l0Bx3@(*q_1l~R=vcF z|1La1tK~(>0=nnw8>6+*Ji2GYEgt%nsO|)4g!f|HDc=l&gaGhcwz@)lxBLi1`ZG*s zUU$RM?WTfILXUYAY5(CuYK-%3eE>tUr;4%$&KX#S$6FWpS+xUwVL@nfhkgzixLve2 z0Oha>#Zc$53dKO@`zd!ZJj>_q=rsdxecQ*)emWEX8OclG`FQXCf^-7rHb>V{Q+Dk# z!woTO#?k{SjFhg%@AWIS5}mVVLv5<}i>QWd9zqMW9PC#OstB_JCKn%v{pRzHB*j}VKZ#pNy~}c2+`!72uDlnO1s` z8nOKKHKa($zwrD5VBc2rp$Z1-625_O)G?`WN>tFfbG81frx=xE|ZYK zr8rpyx{06U5?-8pe?r&rGs^64iE%)|odzekHa!xzYnOc%xs5N&4L15DLf41gwwVJFv zG$@vxgG9`l%rW5#0uC!>oGJ@fIa0$ee|bYHl#(f95tyu}3nODyt?M%HY@b5t)fqf- zCJ`qcFb@6LoE`XCx`Z?Phs1dJ8I&k<@_D&2j*^k}2S(Lg^t8wR9?Gwz%LG}O9_rQ> z#Z!IsQ}F<*1sE%<00CQt)8%8Zj0Xi-iye5TzdL@xS%a?M>mMX3f|0;FMe~fTU%`J1 z*jps6&wsnK>z%{&+5LprRy-`xl-gVl{dleAUR{JzxBM5FsKPq#$=Lr@-p5SPet13n zZ}!Xc=!hJmN5e<3sQ+DhstL2YkX+mAsXt~5FgG)rh{3Jq#4kYOK8R9%7Xu8FqC>4@ zrpR;XIDT$t(FHs*YJ}V^T_B5F5+UcY@C-)(qDLK}<{F%kR43i2W?V7Q5c>Q)x4u7? zr_g(VbKBh)ZWEdKU8lAn4>Y|z9-sSS_4U_boH^BxrND2}k(KUh$&RlCdmN-~QF*~z z?Xp-}7FRJIchHRiI5g^hpZv>ba~pom-aYtdxG9+xA;Q#_0$=!VV1*h;h*&b-* zpg=~MYfDK22!0N>(=PBb{b?NZgy>c1COsw;wYyNuf4I5?vtoMS3Kaq@yosZ=lX0~h zw1Ur!ZPr7eR$1pKrh1iuJ$raeHxJ9i(vYu+;2F{g`kKPsZq9_vCaX#x80>B3T)=noaIE$!N7G5)^t>)~8YV7Tcs=;@^$*!U94^pt{9v!W|W z&&T{8H=O43j=Dd@Zms*`P2%hSI+B)xO6Ngg;x-UM;dV4r1PzSAcnUD2l}?J4JdRov zhEkh%{E4c!hm$Pm>^vz{v`KxCn-}eJ`n6HL>i(MdlL|0L?JXBpUWnEnY|ZsjqmVtB z%ih{%L1RH(?39hRWaQxSnBN?62AKp4ZzOK3?Pb~wY#*Ba(Y{zFJrUszV1 zLk>R%90*|N#9TUpEm^N1*uF*R0V+yLBjPl*qv!g_e5N9MfApc{EUEt?2#gGm4FXLa z2P91@Yla5QgPJBz)4vwF36d~HN(oz*woh?qO7$srpYkrmZ7eh^UDP8V6M5PT^94^1 z)NHq%KEhOc@A5yXB&~boqz&mEDM%Z32?C54Rze&jq0ljqyOnlI2FUjN-VZ zrxv?lDpdCPacD*^_-D=*)k@dAEzcHnMo|}!HMI=k9mExjYtm!hBK;Ankt`mtIP}gb z(f9fJf&xxs6z99Zm2XmhQ0dxAA8|f8AMTDCUHq6xSAiy@u6V94BSD`Ik3X zeh)zLl$&+pv%vf-m0etRE|wJ!0w4Z+83Wpwpd!T=q|Q0i9K=A_-h{|Ul^hoWBY{8mPZzOypGTrhdQPevw)|WCp0d&8nf-X@ z$8NaPBKs^_(e|k^qk(s!3jC0@U#SLSj7R_`=Dj-Q$^}GdBt4v%ukG;Uewx=aLPJ{t z+VU-Hm|)8eKX?cYv~#7kEQd7Ow|p z_34llirr%?6X;2-bo7 z6yA1@hD`ESLvO>fV^0M-{G1hBWh<^hKHcQVQa zSXnWfbtczX*rF{9m-Ztp*rtSZE0J53uJtjTrBitrSMY_ZSv_J})w)#gY^3ioD+}dD z5)U@|r`OT}i3ct;xWP)pD!>h;`N`XkGm-Bnl3{h9; zJdsa^^fc3^|KjuQK2vM{4j^L3>qWxnwT$!5?OpR zVv*C@hlHt0Y^+ZXrPqJSLMP9?mzq-4LCX}aVu7O}8Br~LF^bFeyNT$2*7%J)DfECW zgRRU9`7p66EFueQke7#L>|Z31rQn|L|9WbvxtgGSUN67`nBX0~j#tvYG-aJGOUAO` zZ8osI^s{fb$`J-senW zzI&~tU}1c}w3%=YYIcj_9;qV)V<<`~vd}Q_{!N2N9rD+$R!q`uK0>aH9{vTjw>d7A z;)S{e&KL6lEN!C{u=T1N411IbJ!=_3($r07Ow?2h5k2tGPIBiwFK9zZ0}PuKFFO6^ z7WXO6@B`^p>Dsoz`r9Ia;PU}(`@fXXA}PES%t1`;u&e1#G5@+sNb~2s2}b0W3-?8o z@4HvuOsEr~j}0hHDZyM$9oE~IXeY^;tAy#GQKUQr#*OmJ5sfrVDE+ubt1*O_em{fs z%2fYyX`@tBJ(LDPEnQj+(=AuT8q}(bRcX4)i(cc3R6-8zHF7NP6V}NU18)CWkTTb* z+y2DHlCY6pY*W4HF`OJeWXh@^rP0l*b4XS}lXm_!cM5zE0HHJ}b7ybTp*kP)Kdh;}FDxJM|C5f= zkjv}s{CbP^a<~9l2uLZTTM@rKC%66dQh=dqL=$obrRp(5hN!?w3bl(Ri@^P-?EUFy zKh-w{_mWCnELXjO836#}jLr;Hq=wA$_0ONxJ`gC-zPNRNovWW2?N8X78BGDa?h^R} z1pf9Y2*F2*{G+E=!l(MYoI(^G7wkJqv{a*xBlWVhq; zeH?_q`st-U8A}}(f(uTFHb1x7DyGuy*(>C&v*Ubx zl;W^-l1H8@8$a5|Fuvb%?$xui)DH60WwjPy^ncLxjzN+|UE5~aw!3V18C|w*+eVkN zY}>YN+vu`w+f`G~`@CPwOvFq?M#kPJSDwf}C->U-y7#rZ)F-QB7cuA(^YE;4Tsuf+5 zbpUb#n^GESo2^TKWI{`2r&t9T5Obpj;dlxSL$9IBiT6HhYwAOHvkbFNAJY%Ntd8-Eb5p*=faD-WjAF)3s5&> z%0k2J%7Sz>_4O}U`V-n^)->^UxJ&ylK1u*V`&Tt+|@MOo-TG_}e>cI9P9VU^-9 zlYTV_W_`;_@J>UD)+jA92JO=BMCFcg%27J`D=0OIeV?2g)z})(FaUf-rty4w%5!1( zSk^28vW#OEgPETS2}U2>LA2!8->&uG?ifM1LOwyufFjiH-q2Z*Y|yCviwe|Gm0om3 zcZWO3&}Xq&79NA8#w|QPo>#+lOePWVN~D{3)iLjy)On|a{Hcy|oR?pf5IEhoF58$< z5KDyWNgnnryB{av$pBEBy`j4G+g@BOB`My-Fq4VCx%a~wP;e-pLvaSI$)7P}>Z6Q; z{d;}w1AJUJ(EqN%2Y6*<^QQXEvez6J7$8E4R`bFO@J8;{VXMo zM6xMmLs|dAX~W&Xd+3~7>~n?WDRiJ9@*0$-jm++ix)k8#M;w1ks+@3s6?kX~sbEp_ zQY-2Kd~1LGAxc4LISg>DIZYjrY!F5Gu;EnCTKr4!#T(DY&?-nVBb7Vh|`} z!Y?qgNaLNQhdemD&Zk;syhf%$Wq*F@W%|@8f$4fZZcCbmo&nJ~1(`EUDBdn>+N)gyY2*s7mF~=C;=A%nee? z5|h60bVE?c$YV9s*40qmue4vkJoUzh{vW*A~U$JqJbbfAEfx}KxBlx@O=Nt05 zPBpJ^7$ul|KptU$!>KE!r;{hGBTa8_Ld01}$+WlaRqf;9N;2yyZ8qSt3uyIHVXO!N$=3$3RBy276c!&XQ}UW`09 z7Fb3IrsjB_61+v4cGGH~Pz1)*NRu~TtW^mDnT0zUoZ7Y-GGzX~l>gpf)XC}qSvD`NS*>LCK0$j8wthSU(dI12onx#a<2+c>c zvp|XM6xS#*ZL3azhsom~8#!{&hQsKp%>Uu28XuSfBMwg-t&#={r&$N1v(t`fX+Q{? zFEux5aTl%IKxD9g&V)@V@9&Y@uP-edAV8B2o<;~HCgdd41*Dy`a}pQ_E!Ao#dFu0C z8e|dyfe_0{BZQ7QrUv*~F!BqRu`G)$hNM@c)IFMZLapwoIz4)m)CS`US%^e;3z?w~ z*(=5WVyn+a68cjsolXex3J@1lw`OCqS9S)&aB3L%Sy7_>3#-^_8jo!kR2PDr3MbWr z8e`Hhu$b{{6YS7L2R9ONf<4kbmRMb;&KN5HtkDXDxZrdxT;&ELa+ef(z&K1{r2a^Kcj*GVZnWX{#d`j2rNBpFjN zq8f|lK!wLZFc5HUYAzxJ#6_>sUymzFsT*0BuV8I|+6*eyf~)Mo2VAs{K;A`T&u`9n z66)R*(#znD9M6=sM}&7DB-#l7b~JK-J%j8`f8wHM4ROBcr&cMFR`KI$>S#`g3Rln( zxKJuGs^5Dvf)V+wLh_n(-T^yj??pL$U-J*VCdLlnjs#G!w+S_mASf(j?|u@WDGs75 z+NW}-uC6r%q;2+1KJopG@h7dX|2w_XHwDeXpS;+7Tj`r@o+7IL{Fxl#Z1+tDdppa8 z-yxW?U99#^{)Dys9GYTm5ST$Qb%p%B{&k^m`ZN6nK4~4;3y=OG0K%8Q?E>C8fFTBR zQ1!rR0pEe95xPp5!BGci)HPQq+LR5eUN>U)ju7C!#>u#-2by;9+ZaJk=_lp!&P0}K z#}Xh@VZUzGP7hAFY=ED?97~A$!UQm6Uw2Mzrroj$c2MA!WTE2kIcA3B2&UGOAA%Uk zY8K)8=#?nQnC`;jX0}G*WP*WDEDYBXtsZ1OCQtwutP<)-bDpatL#>KdLF(DdE6^yN zV5qJT2lKbbMa7#>flfCzU_V*p$>D)+hW%j!vN8f8Bkr_La=38!${%FwDzg|{3KZ8i z-oV$$bt#r(V^lg4m9w)nC;$OgOIgBCuyfcvVrM^HQOZYl^C=;_O1(`u!G<)m4?41` za)Wmo{feizxwCI;l01F3_AwzC6%0`a&Z!pM5oRGIQGZ5kCOd!i6Zi2B9@ z9MJ-eqM0ES43gs%Jm}FP4*w@rd{)}2k@GMVvqC*@J-0S8-HMnp0E-tp$xf|-#dcZAw5nz{>%+z|(TCIzw2~k+#LWxaXfK$iQHgd>z=quOK z?Vbof|MB@nI1EF2%ko0mYN4r8#9jip;=qM6%v`EMlF(6Alf73jk&zGBpgx{|HRD1O zoWOadp!2fnH{4-Xc83;U$dV`@%VVLym+h@Ve&42O3a}v@&;AWBu zYo*W3S`oI??52Mu7aFQzus~L#`_UPUp()KDoL0=I%#5=6z~P10U?%$mGgqvc$KpkF4HB8$2TsxTzy`lmDl?&1yAz;b+< zlSy4f&5zm=(1jPsz7@Z@ae?Sj;WoF}NfOb0h9S~NMf*6IG(X3e$j^oUIWS84cpXr~ zPMrAGkZ$Q%3=cIH8Yv@jtsgHksWfSU@_SV`?@f~ZEFKIX@7$I@#;sbopG2ada12#%OYxL=VdR6$0Un>kbt&!uUJ;Zr4p+F9gl{PakW0)wUpTUp(o`Pjrdpq^meU$i zbg}j<=g9jzZD&xKSGa;2xQzi*2b!O`aa07>rJs7N@Jmzfy<(_FQFV?s2Hm))YQ=of zh>e)>t)gQ1lBl#$b7oT_t+XBlv#)AQ-Jx_cgvmNhMfYt%L8o%jo@Cgg^#h8qHCne2 zA(&|oAp2lyM5=t^1=|u_SS}l4(+0rlPea&EZR|8nDmPu-3{xJyp!4qu$xn8FqL9@Q=U~QOU}p7ygBbuCA35pI+hjOn&$2% zPGJ*2l`drb9gBw}R5#Bl-h?X`@uM5|@J@Wpisz(3eO+UncNYLVU7GhRE-hQrV$>D` zJk5Yljol7}e2$DpK$ElG_MafQ9AI$fR}w2xgJV32S4)Y~R1x#xjc0$&{-BY>CE>pO0PlDRleXoku?z)Iba0??A!{u_Y3PkTNx17@*z|~V$f4Q(Qa+-t{r0v zqIa;t7RegYKyg#%T^zsbmxDGCq^2N@CQuyYF$Dyafl6uM|GwOS;REO-Vr#v z$EPYRWJ?dq=ELcf5+KuvDGWFkIlkwaA4Q?(nXUXyN`PJ~vIR|c^ULvhgTKxeKvZ9m zS#@A;E)?*(3Mapb<-V$7n+w7%G1ea`Dnl~zQ%)cqOLPKmLE;8W#dW5Y!zn|iQ0c~t zkC&LfR*bO#<}6dwBuT)@upTjlquwKLWHiOkVgwdsWC;<8$|&FMJ7PE{Q!2?AVp+Jy zBCZ1}p&G-cyDw_HcAizs1_d?;sMWOPBjkaP!K^%cCz=}tKXKB$uu=pZdd1lNyg2awCRnTaGNwOb|py3Xxy!yk9*%u)y~_-s=udt5C< zq$R-X#U~OA_^qjmJ#~KwYi&j-b~5pOsySP-gvTkU&6Th8yvt{$?)#(kG(?xJf?IPE zmuv&{K;2o)C+O=5X>|h7E=z7p5!tKpX_<1zf`RK0tV1Z&`sV8Da>?kZ$(Paip}3<{ zlg66nFF?AMxp46mXBK7ILpN2}j0DdclH((Y%>yUP_H&ZRt5TvncIc0eAPCpKY z&zkSRr{7#_|?Lg|8mp3iuRtFtvh=?vOj{^-(LvqE2Z52c{Ixo?^a0wuXmB zSIqWXN<&9jbfPoJP>X4G}VbR|rCR8}-?3EH@++n6VBya-J;%-}L^QY;pa+Z*0 zV94C15jjvy`2_(?4zR9nqC%%2vxxuQ#)Rf7?e>^*F* zFs8+)Qd)TDvtcne0i*8v3sT-$x;O}NANh6lezp;?` zmm&mv44UPXQN2Ybp1!=yi%LQ5{Xeyn=~OI~*BWGN=Gh;fk)U05(f`y=sH!`7o-|{B zwW(L7o&5RKE?bp+Aq=EtZ?{PZUe*NDh1lpnP6gT8SbggK9RN+^$Hr4ITpFwybA65N4zvJ(}TLh*8UY@J)jE)RP z503?a#rOI(yYZ|Ga>Gvf<@RmzebutF&71hvF+vQuJ^WmvzHnpzc$`AJj|g55r{2L- zZ)XriLm9M{;{ZR=)TqKq$OIx*>6JnVTyfy_w*Ci=vm1wZ|MgA ze8tmzvYa7rMPdtOJMl=|TNYqmxL{u-3p4>(ve=&VCl&7Fl(wqIg0}nBC|oQJvBHj( z#>V^!Qqr6&FZ@|H*BUqu!#HE)y1Bl_Ge`8maz>s@+J6;X5j@HWD|l&L>iOKC4_`xt zpO4L`KJ)!JyE1wU`WSv?DE<=f*0=d1nYdkGue^UYoRCtldx73WE-06dHlF#X``(mA-MzB?pubhYb-UfEE!}Xa5fc8CU|+J*-xk zQFDUuWo9iOHEf@C zHD35>v+r-30Au5dm>j4gV1NY~QD{^)B{%1VSuEeB{krA5B(W9b#Z5UzSHH(qQ}U~U zIOt}SpRbDk&CZOCRD(ceP@DQ&O)>ud7n%7wK)9vVH$pTUOB{@-n>2 zBr}7(3cSDsi4^{u{!!&&GkV9%K-veWB?YyOY}#0IQ&Jrx-r!DbI04iA$XJV##QG~2 z?>|PKD{h=*YhL2yO0|=B9}**pk0u&g!Q{dI*43CLgB+WI_EQRwEg8OyfWPxIOS@YS z4c;s4pVs(aGJIOWe)BWUBASGd|hz8fBNb zZSo~LA$UP{jvgAaZvZ`*FKtQKKW53ax-DG1ET1dHWZNKNE&r0AyXpTl1taLH$??QA zvg%(srEna08dy6u>+14AWOQq)ZiaCy$?^2-nxEnA+dehJ$Kv@6ED-qlg%~qlC=f9v zIr6DIUj5$Ee$$DRHFIx87VIHpMLBc^lBX0XT9Q#zj1tr7fNS=X+JCXQTJ{>)EHOYO z=v;}6BjwwfYOo*wZdr=X=tuKgqP$wDFc)#kvIRn>-O6p~qFwaHF%gagi@vayxv)rj zj-d+dv1h|ziWx1@-d_A0>ibSuDiP(HT&P9>W!#L*AlgIHl;Yi#14gms4O65m{GUhJ zzk7}w(`^HQ0eKINz#@5MSxml^bHSG4(mMH1gnBAgaHZ@T4po@kfoZyOtoBe+bxg)@ z{m#iZg35=)WjH+5Sa1yDz`UGz6=@33kU9!X;~qOF0*vLW#k3Hke`R~sMNJG@o}PKC z!?!%RZun2`PV{aOmQowaoNdA3#97KP##;Tavu=?i$P zT`H9BmXWPdCs@niYCdlLy#JAwDc2cd=)?3CztptHG)9tzD9a?%599R?GWr^R`{l8^ z{u4qvxC_-KOA-3mE|3!T>HijAJy5Koni87QvqYY}V#L?Bm?_WX{75}pf+fJp6a464 zL&eJc2R2i1@UMQP2pl+|MzCg{4+PMi;?laLr9kdV!888x=>@z$>Qr`3cZX#b!n1`- zxlviplAIS@)PQiqrCmg!OBmcqnX%*b#=o%C-{vzrxcnbQ`B9b+mM=y0|0v2J8Ow%< zKZ>#`iZaa9KNyQo^MXf5c>kaWt+N|BgXjehPnP@Q78I9gET{`G|r7 zbPcp?7$2<@gk1n*kS}Ymc@Zg9S!(di&WMK-77NWg3#9YR9PY{t4&;Np1#Mpm3z)(U zblb;V{-z+os7b0J$uboScb$Vx)I0T)AaawE(d4y&O2hT`#}*@>J511aaGJLLjqK!! zuF>WjbtzN0{&gLo4b&SIitOW(H3c$I4=gK(=WZ*4^;(zt!MGD$ZVIR9ZOdDbWBRC@!V^LGL}yGjzMNG-Go-{>{iY*r`L9Pr3NW`^>A`sspjSN=!OphhMGUdtMTk|Dp0?HSK|lP z;l;Kzif;>EhgS@w5*brt_S|Y8u&u{K($m*cFqcvg=TeZTLOx%p0=Y)A0MRggsojj3 zJ*$T9_Vd1~`a>!&yM?3lk~h*0G=gxY0T>UNU5mc*X_-=LI`;ur-UXq)dg_D@m2GrnEkAlOb2CtC(mF5yL;;Fp{8xBC4iKY}&xDV* zOiw}d5aXI)Ys0d$_fnRTf$0GwQR%HT`nCV(b;ATbq5}+ieP5}T~U8I=na8FFXTw0x&0BmlTWVCuP-~}0*HHpbLQRu?Z!(` z0v`_@tN3{k7*$0dM7H(Yk;TU{Vf>H}G=SsVj3;82Z7`Ngt zn1O-S;0JE}(^x)4opG9u4Npf$6YoVt%5EG~!~{8fdTs1N5`%6-*K3t^Y@FkJS#h+< zhe(mX6+A(LJMQq4x(G&*q$sxPaM@p`2K<}Zur&h30vP^B3J$tYpEw{O7k&Cy#b)Sf zKk*ceiYb!Ee!i7=P|8F@3`c+o$S8hem8}Nh6 zEq%sJQTJCq5_-YutSWq;xS2XX)W06X%Gl+JKxpK8l3h<$^OJgG=m}e_yiydyB;OnT zhD-2tfDO&4^*XTWIxM{wA5#;bu(fcfnd>!scWHTT^bHW4r<&2-W9R4o>+^Bw)BJrt z%`8ac?3UC}{-nxC#)8PDbN=3fDq}2~x~Ho4x2u4~a~N}IiZ+E;GcX<5_A&;X7bZ0N ztO^{}m?qN#_XXd#lh_4c_z5BmoHb;03+PA%fS2386Q6@%)o=f@_m(RgpJNLFujc+| zTDAR#fM@qVQR{yDumAnzXMX(Wf4=dbun_H^AtRT!@Q%BHV6EQ6Q|Lyn?w&|xLoW8$Fh!wHq<9N7&P_m|DDyh?cdO4uHTRstLt^{q?R|O)EN25 z5g%d3%FN{mA$#)LTY=0M$p}vLHnCTgb7Gw^a&TzJ-#*y^{1WEgp%uzH2dE7~t4=b* zBroKG3$-faAQ8EOm*$jhN}8$@gzD)pyD?n3&9dC}IpnageKxSt^o;nhgf-^(hRd@)V3IgL@nM8;gt|Rf=mUz)P^18acxxk)!pS(l`Hfx*FXjqDu}53B(*$ zDJpPg767YaCPM6_pONF;2SQ;|$ER&AduDu{oG#uAfR`m9?4 zPY`vGVtcxc4e zy!V$HI+_T>6q1Zg2|98$GAw-hNT&kuv^Hoy`aUu#JY3c2l%f&W6!V^CCGO{uXE3=xTako!vu~x^PJ;O0Qx< z(Fh@IXokvRizfoY0#wl2Lv;Z7ZsYP;h98GJ3P1e7U_gu!+rmG@E#4Nq3V zgiasVR$YAL6pQ0ta8@aIzrbA+)qfmh+Y5Xe;F7cyKZV=8);YyW(}3knng#W76ACk^_ zTF|m5cjOII6dEt5G7>Dr2;R-&l;!i$hlMXdyv=1wTf`kvcjW-!=+#+0#$P)k;RPu% z;4?9yN1GLTJ4<^nX2D>TwqfBww75VC*ZVE;&Xldw(Qy}{9h!vPY~W)fE(WX-40~*V z{fXac)V_9#f49x4(m_PG0}ZAr&XE)L7nX^rYf60i-i6`(I=={s!2I5h&E(|;h!##V zStMDA7R95GPrLwxZOu6;`X>tqQ!@=*rN+$9#tv3c;WI3NPEZ_VFiS~rHt1LnVxtJs zZJ1!TAPW{%HXjHOAUYyJ+u_JO@kUK}dQA#xqX>1(RV9&Jjj&Qp?6)KtLro}s58HQ= zfD`l(8yz8rH)V7+liFGx%(6H|jsMC!x6Dl*i?L&958(i!6^w@L1-6n33QABt0YiN@ zIOddKy=UuYHJ)29SF5M&yfvAh_H)bQt1;eoUiTO8W;HpFoevKoYBkxsmsV#X4a*EZ z?k;opOXv6VCElM|S=~NwI=#c^=q#UKE7`L_9smJgm_j~r0XO`H9vpQJ_=4>HO-hw1 zFG}CZJ7vJoSA+_g@15nkH;&X3!Ka55ZZGG zDL&|QY*u`!V14B?9;fZHvpALwTvy2$fx6Jy6C{Fo<{+h==yVmen&6&d)D|iNqd-Z3 zEl`9F+<4vzL(iTEs!S}7b~_S>2LF%FlC?G5tG1}iPs2NC13{yQxDPQ^nUq?5UkM9H{01fUjU!ioBLlrudll& z49+Z^_`KhTJ#t^iJ25@idS?9QAdywuf{tCpr4-mPVcZzaSblCeD{YLN3}jhyd=TEhXe* zUu5|q8}3)4P;*wkbZo)?x!tK~XyZG1MrKb8{?r@^rAP${w>iTxZ1~0pDEsp+O=L1j%;P4`SK?D!NR`pd{gA|ze|XzswmTr8)Mfq zwm1MVXOwwP9!ZDT#YtWxc7RoQVK^b@M}z-BNc4`391m9ON6w$%J@M95a-Zmt47 zKS%p~q-b2FQkZ};`C$Go{O@rcQ1ozlG&Qm;eyo&fH^z&@S^z$t!ZNI8Fmg|NeVYDj z6pzdz%;evpaO#3KgS0?sK7CVuhdP~u`4PO=1&+!Bq1;Bn``Zu!*2G_^FpJFoj6{Ez z?DgV=r`glzlU96Cy%j2m{Iba;b4oUX3b4H_6+F&RzdgYCg8!OYvNDHDZj;L`2%7d{6rOb$5NR3;fz% zqy)(+~sWQILj~h(ZBE(;s=?`63y>V@-V?W0L z(`L09O(?8!O*+u$W_&Bm`Ep3FIeT5atU|xy}mz-Wivef0;8GtZ2>xp3+%NeLed&rCJ+* z0*2fAXNhOUP-<@$b+=hGE{3KHf{PxE=y`uhV7xfEA%X zlw>OWFaTxK9J-TAK(uMhi;(Dn(}#j7@jk_va`P(~3}a2q^Je{tERR}3Ha4^k-NWJt zd>tpr{>SXJWNK2J-|afn^DJu6h(CIPHE?B8y;i*ae($ZocthwKxcFr6IM+sEn zKZCq{bipC1C_seA}qwgQR9uttn>n~bml4w+Zs>blpvin==ky)?V#vRGZFeW6htN+xW&%Ue_SFX0jhUcB4sPs zqB|;+qV^je%4CV%`;G6-AwMJSX<3~G6TJdMQ? zjL3dhiQ_L5rLpSc(B3*t-v(X)%#qD*x9@OYbHv0Bv}qvS*KTO~#&IiN(Q)(o*+G=JGag<{>5Ff{O-uUd5T{3e2!xli2iUE+NGK%}H{w36 z&z<}_zH5JqPg=gXwtf|k9>8Y!dd#P`7^+T@Greo7H9f?B_TV&=Gj+ZKuu%d4630{B z7Yf^RCo?^h>LPa0Bguyh-%>Yww;6t9hp{sUPibls?6FQ(A>S`kKoqm!nmQyS`|O}t z2mI8$=slX!1U=Z=bTs6_BLneMA&vulb>2T0ET7Ib#Yn+}zkudpUx&Uo(3KfV@;!7E zeY5t4&MO(*ndmQ!np^;vfMftLoHE_x!kY4tO_Ua`Nt|LBKlGsrP&aTm4k((jPmh<^&&Xj@5KW4_hI7)V%XMQ4< z0uSkfO?%RH_?y?Kx7Ma2+ko@Zbm8?rXQl%1Kt~|yhF4rmrFekk8)crFm!IJpz18ga zspj;XW{}g>*8((?yYpR1&06Nj3s^i#5r-7A1RT?AM|xDjndSLYcvy!qt%;f>4Oe&b zbt`q~-i}uIp#sx|Ez>nc1J7r@pfWY1`Q9}(>YMs_%E1d5>_~5~s%$~d_BZpBG$rZ* z!@#ilZz#pYl6=6yd$!+OwK+jjK-y~HWou<=_Zfmvnu!RT)+9kf2yiATYx4P(WSBgO zXTn7QohEp+WE?=}-)f|)hG2anI{H$)Lo<1PYj4O}z9ELG9AzC|r^bwAHa$w2p_5aG zw6=w9`C!G_FY-v05;3$g*^pUsf~ev-Oqz%k8czo&6na3W6j~6!lBRNG5!UwF=9v{L zu8AC?WcEMoi5$f~f6_P zGRVH|tlu((KHCx$q?Rt^6ka5BE zo`C-Yee@4ZIf;=Bx=n{*fe{kT^2c2BdS@xgpU1p`6L~UXp6&0@UyQpWjkZ3|O5)cQ z(m*TYz+hT#rPpI-=0 zNbX1eD&j#FgJw9G(!#sNRoybacsfZ=xvt;yAf@8%hbN294Jeq|1#l@L(v3i=;7f2* z;8Xk3?KDsF_bo|X`jjb4sD_G+t?|sioY40EKQWCQWKN>6t)JNY0I*gei8%!O^!vT^ zq(c2LGCj|F<$w+96=)UI{t`=e0;BD?6V$p7T)h_+kap5!Xme$2~P^&OJ9 z=Wbf7w+pWY&}Z`9w>7=kW|jI^o3GUd|9oxY$%QE1%U9%aP0+;`%DhNZm0i%*`J_{#B=6)K7V;8nLvqb`XBR^dT< zSi@0Qil)zxcSN_%e>xueu^5yRxPw(^7aK@+Upm#LPk}W6dy{8>bwn$di9GP#sBw@y zrq~L$S=nKFOiEz2f~WKAa{x!1uj98|eJAUid`sR-@{WUG;)~5>kV)(|4g_-gn118#jcJ!BlyV_^Rx-rUN zr*|zf6W%H)1S)dE#0n|km?!Vm67iUbkglnfgp4h63SEfzz?3;XNM1!^&e-tn;$lCX zAv`hJxAaEYhrQm&#UILK8L1+qoZFBfx7i}5Y&zOJ`(7(j6xnN-8puweT%L{?L@TKK z)^T{G`n-D`p_nX(e$pens~n4*<@W&oq4vz>dOSu_uogz3D;pvpJD!#ZiFXK^rkBXH zLi~h;$fBT7`)@FB5izFzNz~BwE{#X-fn2l+VQoYvT!9^(u114w_&}sc z+Ha?W>X_`DS_xWc?u7KUUKd$y{fEKqy6y9YcqwS>72*nwDhv^zHUMEyi4VO(XMaPd zQ`e{}BRdzU$|VkPuq`Xpz$k5!i?EHy%A}In29;RheaPm9q7B_pj+1H=PBB(EK$=(x za5PbI0u9648)s%KRu4Ka#wFx)k+N#;l$~`2&`Aw_advc;MI2_x^O?bcm`#D7v#0Sn+^F zJVU66+YZE?eapO-UmN&jEv2iCO5OQRP#_96M);?0{HGFW6|%{=b0%2n1q7_dOy!p# zNdtNj zN05Z!x+#2yXF9Gt*^_3@&qE(Jc-vzVgy=dE7LtrzpX>80Bj%3x@> zI2xeV&t}V~{9FR7K2Qg5R?b^J7ID?<07AMr)EDK2!^Z787`1hJ)Uc!VZgkg$@G{b+ z!e=}BBbb_*K%lVlnP)R@W&(PyPWLkzc~hXSPv?2V$QudhrULVf1cLQ{OJd4;k3(7zK z^gM0iwd7drs=;E&J+8^}Uay6VnO?-O+x=BdAfof(;i+e%4^}dFt=ZErt}~f9@{3xR z*tGN2#KA-sYqJ*SoaFnHuP4EK7HuHU+()&a^X3OTm^QtK7x#_Q$x#qbGUCW#M5q6d z*n1(<{R1BC=V=O-&ILFsGM5MZ6&5kO*DNR@_kqm#T{rx4oUu=%s<1&poK}y$sC3|@ znwj18ayln+c}#DzaB$0=EM$W|7$}ITrUvPsn#jhJgq~hCfenGL1fUY>DBeZ-mmOS; z#KNG1*TeKT`USND*$$?3a)*3f#92xvB7ABn^#eYSk#?MU*bU$gbT@@%b3i+}>5%`{ zHSL`JIVf3&qO)D~F+tW}V~GXJ{*uANr~fKF7!F-E((C+}hH@d;yc|^#(`AnhMR%hX z1zz)i`GXCAs!~hkf6{fZM?~6*sAMzevVY=Z`Sxq~=cE6{555=$lzL~WjLUf^-mF?H z7%$!dpbj)#n@ZiOq7_{S?nvTvV$9Q|8^XyJ^Nq!vv!nEh!O3H${>@AsJ&mTIk9D2t zTz;jT6wJgl(#yq9e$>bqkgu%N??G$yf! zHl)+nanlHYM&jQbkO6h&M!nhFWVQTX_@HA>J+s+iV9M{dywYr|xOi_5GIm4&OgowS zNCOz2ayjoHlEhl<9~52b`g8E3TfCiFiq6g=lkjyJ)&@!ztgz%@7~Zj(?=LU{A@oh& z-J*ufyLekd?><)duMaBDKY#uP(q#QKv(jQ)gd3L3jP)1#!Z)}sI*S=a>AuB_8H@Ox z2XaV#new2+C^vkt;99T&tlp{ufIL?C>n4LLk)NqsmwBN_5Y2!%j3iL@eXwkP>wP(@ z-e_d^t9&)fS4SeE56{E+_yQ?@qslgBlsAMO($7SWW ze@< zay&`1Q;58^MhBYdV_l>KGHfbkfA*>FGXOkw5K!urM2(^GNEDADyA}BWupbuT`0BDR zul>=RYFTmNZl_c_^eEf*ygHjFhPI&HA5_Il63Rj#UCYI(VNYDG65RStL5YuKi7LG@ z37wNsNjoRlXM!I8i-tOO&ZO;H=92q1uXS-`B^Ie_&?Qf1zBF>gU`04GT5v5dShJN2 zbdu#&_<(#kY8096p$m|-p-GFsbTtzYN~M>n085%Xf!YvkoxX^;v|vuoy|vn$rkkeD zRzk^SS#B0s{|LV)tNC0Za@45hrVPC^quBof3vCi?xo@-hcf0=&urLLI1sE3~Ms=yR zyv|SQ#E&I;W1z15dR)D0*&7M%D(=Yo; z{{$|#$bq|*T<51Kb8H>dIqR?wWi6vu>sO;Zx?XKuwjUDHJvcgbEcatah9(P{eIcq2 zl*CDHNS;*iUvCgO&5*OGOBDc6mMDQGrWo5bhLoVOge^V@sGlh|G?sc_*=)0LlGijI zyLMB?|D5z==E7=SexKiebg1{(#_PuZ<<$jVB3II2MmMWN0bj8!`XDwFnn`$q^F#&f z*RImtt+nRdRm$Yl377GH-U!ADK8r6L zsY1Hr&v=enF1smySL8J`3SSJ5i^I?S)WGkqT`avWM+?pAwa< zcqnV@$Hq2yHW10hMpdd2Eit6bvOK+_&Bgg{#U{Fn3iE9kU0XGF zTE5c`Vbl&Gqp@`|5iJMk=Y6H2yFRaPLDY6CM^W&7j}nIPr(p!p!iSqt7cc%Mn0BLyBV{q)zDbM_*IS~k=C|*hT3@YyHb%r6Z1A46 zNm~D}+2!4qrbSTzkpD1(<|`H%iM|FnC@fqWxX)(LOf`Rva8cLX7ZSWF4T*ENW!t|S z?0NEd47%@Hlgt#^gA+1@UZ)kB>wGs^nuQ@+DAmRFrv{OU+(Ppce3^9zF-=j>C{g$U zd_G&u>)uYI8+bNfX<2qUb_N>Cdb|*%0ChMSV|n;z6Rrhjjw3z%r3oQk?}2UU^S((z zJp82z0spZH+x&q_X#d+L%*9KyLi+#Mgvc=eY(mn39Wp3CoU!ZwvI*}T|2LbE5cPkz z35j{Qm9{p&Xu`g5d7H#$M=9Y2xvM~l25{O$I>27M4Qdc6=^hv5`pefH??sZLFHC7fk{8Jl6qUg&eyb<|p6Sfikk4-2p`PU}=a+GxA zZA}6IGZEK^tsg{t_ zpz+hAh7@cwh2iJ|JsBGbAeIyp1RQUv}?eBZNjpRMY;b&oACdiCItLnw+TUlIk-4i zqYm}a)Ru=kdP}yuuX{TxvtUjs_vjc_0j0gYnI=0s!Jg;AnyJ3$qME6m=U`>c#-%%d z+CR)7Iob&Daal_t{lE-R`CmDGd7zvF|CFv|sV}s=k>iV+H)Z4q5lc;2=Y0r}R}K|f zKQB4o01V%~@NB@#pgDgk!;Xm>9SEv=1X|$G#B9?INtb$$&0!8g_n9@7HGplg0OX1F z;V4Jb^1JAG#4exE`iQh<2!ETRt!bd}3Oaao2!QfWd`J;5(StvPh} zRJQ-JZz;!SjyMB>>!z1YfXpfz0NTDh^O0}#QDQb3AfHtkKLSb`glRjTvZ$|uYjoqW zld9+)@rjMtq82ULFX15yW1T_R0_+}{%~W6|eXr6D*`=Ut+lII#Ee}dE6(+-%9Ai}N z`g(mP+aRh}WfR-uqt(#;6QapYu_5?7hg0F#d&_+JW;u`bQ`2_C$)dD%s7}vN@_bM- z;N-&YA%}VQa2(K6%W6JWZFo)CwuFTr2qAg_!(bup1V5^@lflXL+!3V*FaSakT)W>T z>mVwJY{^Lt8ia}LjfPydT7k`o82Ed?-ba`GMv4yr`)84BInS3Oio8Nej*kU?R{W4DqNiHXPC zhYWUL-#1wiFX){m)NPXI5k60dQ{bd+R$ylWt~}V2E)UWwBY-PWr3fyA`)Cs@Hz|a% zS(acc4&fLa41vUUL+7>x6QlGcL>ZROw{_#j9FAGvC9khXQCjh-rvQBGp+oeSNzb*S z@-!iNIv+T*(7`b*=R*0L`oHco|EPqX@VUqsAmEYtyw1+eL0}VoSeE@v2Hvoc>K0t|9aYEZNL<7+Mrbiw>(5L zc=`gBhr8_yL!W0R1C*w5K}8j9ppo;?(v0rpX2;;apB_}^04rqaO1g)qQ$AI^N-a;~ z`Fg(QLMYb3Bx>Nn-VF}4R9cQ(L$w^H|rY;as+zm-MWXicBrD%31nJE^^m zsYu8&S#l|JsFo@fo`x`53T5~a4RA2hb!2y>3ZAP}x+IRY0iZ3fPRt#q!Dj3+Puf9C z{XBgBGmrkf5+YrV*sO}Fmg?Z3bh=9hkd$W_;v92}->^BS6 zEX#@(W=f>l3;4|zlH5dlrt#?LZaIh#4xHPD=4=Db$y!Lqs^rPW8(*fY=$~8^)j)GQ z=lihdIGc0y6EXT=EtqVA)O`O)QV}#o7><$CA|RcnKMq$5fQn2*aq<4sw16Ead!3>* zfw&^?R+w$NpNTZ)>8T`1y4h%%M+xI)p39~4EcrByo~cN-@_~!2B2oPUyW#MlN8FP= zh-vSC)$1qx<>+&WWKo= zUIohts?tDSRtk)4VJOS7KioCrkqOyIwkhxksTBalX0*lW$qPTa{&&9}O_o!wpZ|ma z(1bJ@osiAyRfqK}(~F7p!y}A_kG{#R6CyLUFgk=G{ihnciX{=eGGv;PaOX+V9&pSc zBQ;dH#w9=C+<_WO=Dp%xRl-eUN4|MRIxp;^59$$<9i=DGT62S){?Y-6;c@=&5n@!d4`Zv*99RnrP z=kjVD0J(~0p|x!U+bEt?diOZh6$>>?&I|Z zyw236C*gtNP(J1_xL0+WIf2j^rRRTM7Q)d1pDuSNMr{>1G*dSbN@zD)8cn|zN{kGb z;8lbVq(yE@P5ummkv8pzyYoSzMVp4ir;bv08ksZz`qIidRUC7^B!P;twA2-e1*;T- zA4#J0y~otU<_{J=^HB4<0DakuL&Xs+3tFr4n9W&S;Z3@GN)J=f?jO0dLMh@;GBB+G zPmF*rxRNYg+L~Zq*+}U))&_-`i?iI+)1BQeK%*g(`nR{yCET^8$qF*m`tmsk#$P@_ zIF2{CA8Jp;w@m_W;=kS!SRZ%QP*z6PY68Z{#@MeeE#a&{zb48J^Xom znfYwM_vfak=MU4vYkSoEAP|761_CNp5h)&}D_m=%<<8XO@jKO9d#ZU9 z-+88w;gNb+)6tJCFKz9r(<;$FVrH`}hohyCa7)*!Ax64#SKd%x}_X0QpH3Wi4x3`W1y zHRK4qG7ojkHeIbseP>o%Sl3dU1NLaM&+C3pCh0O$l{j@*7?_gEInFHEHS3(AvEg9D zt-^#tXxhc&%lAXr@IU4bfNf|{b*$n>HXau(PGu4SMh842nwwvW2$-4?Ah2e<4O-Q*w|Z<~m{MepfcG}%7gFD1j!r0NUX``8 ziCg-#&qo5Q1YGp>1DP79i>2ymB?zCmsul&wUpF`6Cc;LpNjE=3$m=BKR(T_KXf~e& z!oZ%>j|1Qp5zZ2MWYrjRZp89|)4D9%TFOiYw}|Loe6B$00xO`Q7%CEv+lN_9LNqB+ zB={7_+5|FZ`m>$XxbxM>+|;sk_ZZ?LDukoI|HubBBJI=%8$$dA3dYjTy?R<8sg=$E zteB^-L*Z2}{T92x-Q8h||(D56G_Z#xwDW^GE?Os93O z-3%JVMvyt;GEH9V;W|97rLIQ1#3frfaiuf8`@!CL5mKW&B1lm;6sJ$T9NT?u(Bbm4 zX{a^Gy8%iLCgiiSt`i9WiNcQt;yFevG^P%1xeEhUvAZ-hnx& zNdUMuW_z_Iz8T{a`<3K65Ibg%8l$k>l`<@Ph?2VSz#sME;_J4+1@stfR(aig1YrRY zeKsZaExeJ=FK97fRzv3q(jPc4xcF#o)vdUW1}3AYe?F-K8AjMrem3y#Vd-?j{2)^U zBmP6Lq{WnAtTD6g#7EnW++Y3#HIHajHDNK=$*&2(TQOM5b}K zyP42_K<#omAxoE|x`04ON<07fjCN|CI6hUF5vM>1X7hB({#u>0idpRo=h~8aYj;}70?|Lg`(p4sT-#&^V>fg|+0#U@nd%{Ju52~_ zAjNUYM6sXxu9>M_{XOI?X9JgS>ktq|TcD!%NEGujUpWE7FI&_3u+fVHR&u&z|B}&) zSC)ZZU<>@S*5*8CEMJ*^l?xco3*q`E zP9sQvws7daRN=o*t(N-73HVHZ6xr`k`wf=J%hjqD%FGkUwrHl;mpXKjPhU;cO5mb` zR{7aQ1E-wd_dT)epI!K#Fr7JUj#Ok|$}C1J62)y!Sbkx&d)*_3d#^VJFzEyWg@3v}dj*^*yvElafJ@1VvEcjGo#KC_}gT|em z5lnVs20ZXl*TcP7B&@0;yn8>#0?!Z=7bC1f=cl4`JLA@>by5gmLD^Yrf_Y0Mp_9fU zs9Iy5QlQJVlb!eOu95yeXVxWQz;iB`9;??1%N)EHdh?{8&C~( zutqanZm%W6HZ>spdxoiy_BvSx-L3TLR_?%MXo6hrEYS~??eo9}`9&bDh0}yOHBrzf zJ#;Y&zO;Z%4#gM_4Qol8FkCQ^nN(rjCyo zP>RWn<;;N~Z-f?Kqy^PpXkZ2l?9InWF1}~oCN&+kpjXJsfY(}`xo0tNP;100X}3caEMIR>I$t3HpqHw6CDgaG67_?~*30*!||M zxo)ab{)CJAC`%Yt;}hJ3c_%M8A5BMoOz9V-9_}VO@Jf3iQg(frL2io$c6dT~scC5G z*w6=ff^0Tt`7Co6P=L&Q@SUV%l2_xgtnGE?%Y)o! zX-4u^+ZYdV|Bj)hc#BrP%&`7vc+CSvV_6T0Y&nh?tLfPMV($lj09#Usr$uN;^78E9 zkJXe9Fo{zL^IzTtt;ExBU0U$>_uhB?qhU$i=DUDF-))8U53S$%8WiF_{Q}!2A4#6u zC}cBPskdS8eq5#ez8Cg|aqm27BOmNXzgm9P<~V3%zD6_MlsmC9kg2giCr@LeG-d$=fO2pkSiB>g zH&6)heE%9kl;KC2Zf*&&^h7LP+zf=5jaysGZgs#3ryS!O&^=6M4OX;CAK6M#y?-f1UVJ^LJwO>vo2GTzZyF@(zn(=^X=*bly?`yft zJ7phUY;GW+@#D^Vp~}i<9ean%_p20U6a77tw8puP`%{i(S9@VOxk@X0s?Nx$yY(0_ z*f0E0V313h+}wr6jX4-)?QLJ#2<{h?0lmZE?1WJXaUulz#~ zKlcA9$1KJ|>JFAX%opvlmE+XEPOwE4Kv6pQ29~JOaBVu~@T+2vC1;(MX=96Vm^Mi+ zEPb0dR|Wm_oGtvP9>)9(fCM01DctjR5yJ`h{ZkKLPyD#V@>1)Ya~jgf29rUZm>*=p zn$3&>mvxr6Khfpgw@r*^wzwYFVPlZ?&&HKw8vAWqO`fWIvgoche00E6pSI8?23_p6 zhvJo750z5!zIm*6=`*6J=~J6Z)p!t;DD6+3T2m*VMvYsjvq!yax2Sic7?D}vbI1y7A*)!py+{G8eKiF?fq-DGJ)?k<3=3*bbv z8I_ckB`LV)S`hkHbHL6JW1VFBXTRSz1$l5*UAWY?RTCVZyEP5Y_s9(cz3@^e>S|iq z1w*~S4F)jxL}oxRF%LF7;?;FA!P!+UF8M@3d_i>TVt4coYJk+!;?NYt0)mVRUOMS6 zrCQ_Mj_G#a(`$EyM7L&7u_JJ^BuLK3E^A<0Y<|INm)J?&qq?Fq^W`1}Yy7u+s2FTX z*{|vqN-TTDf@*|48^n_X%;zD9fIl1L3*g6_4T5~w{Wsv2lmBf&F}VC4E0U2-Km@6z z#+I;)g8Z#f_clV?K2eJG8|(RGf+e{-TE`2bhIBMFy&PBC`tI$;6~o-V^4O^U8?2rm9{FB>ZK=|knV+ILA6qN<{xJI-+C za?a2Zu1j#nRC^6ICB`MznZC`a&2le@WPlv#4i^`epr;oCb5#alfGX4aK+P#%^e{w) z5u)+Rha+g?;9Dq;DKpwcx9+K340efxIIC?c@q&T zh;J^ZnD_>MviW5M(0v$kkn(kYP_#;2_Oz0}=@aKV2R;q}TBS0)0tYLna2#k%H);|8}k8gh; z@?V#)|1g_8y|4(pa?w^ilXeI!iwuTR~qH*I5^#}jGhGrM9WtPxh3Xq+&+#oaQ zJ1OpSHOMSGC9Zgyk!>BB4mNRPClq zFZVw7v=(~$S}8nzrEV zw@u-2&>KNBDFNtKB)=!n@-Ucm+)V@Z{=t4Z z3Yq6ZW`>PW_(N25Cm9Uu^usNL+4$zksT`e6tzhrje1}Pej&ADr)LSd zb@I34HI}!z!^?j=h=JP&W39MZb5X2%0ZdBF>g;*cT?h}^CD+{0=uDZb(jeohrg6n1BF>L=wmwg2J$-}rCCl)XHI8A4m#*x zYhJ6B2wKczPxVwYP2QYF($jIfYb2o@$bip{x65HbfHybj&RyF8gpI~WG?@mkg+}Nr z-Deyx{M6Z}#Uqj=>qMe|->x=RLE(D>euISWiOOFeasA6j%xkGV%(zNPHclO61*t-d z`0FF;EF6qY6k^PbE~J{18U;uSXTP-+aggq5=rtm1QF~hKV+2wrNzV!vRS(k2jz%2b z1Go?xD2FIbZbBE*M|q7ul~ZVot#+iqzidPXqFw4{B$~ zpW(0YcMIG=NgM{Xl3gq>z@Ev$}tVicz`DR<*@kG1nhbcF%fFh88ZA1n3TE z`byQ4M6|`S8AFP4wNKGNc?~np6mmAjK7IL!!YRu5k7%X@>Nc!rOgKoGTT5zh|9r&B zEvR%^&*-S#Wm8#j)uRDS_8b}py|Xf^Wvg~16Fyx(FhpGmhIz;VR7VQ#MkWwyx$Y1h z5oL|iftF2ym|wDC4zd}#4XOZ*Mw@FFuRj351Nh%z_@dBW(cjz6BAIibJ-k!jIsZ_cv<>c8ik2PjVRBdoU^Us93+vz| zEW4&QQ%tpMv(OW9kjr3MRB%4O>!s5X1<*x4D9rCJx-@;zwfK!6AvXXDpKk0Bqde|# zWP;%>Lg?ZdQ3`2>5|LUGd6nl`ktXQ%Jo*-GNhI~oFn?lMaGKJDhVyYhn*FHr2L*$< zoNt;CYNo6^T&#*~=~ihlmdexbG=*RYC*0!ZW<+gP^EL@RAN|Og3&+LBbs-=bahA0~ zu3y579Hp}oZA`!v$1spHTUc7QutoEbDlezb9a#--G|ZA=-A!RqFD{@ zc|2tNXbCHb{$Y?ezax5|R{n?@y5nj?(q?H~XaU^AtaE3I=-mLe7}B|e?SwY@!7aJh zf#vX%UWWSXByj{upwKd;nOF)KKYh zzC`#O483Y%yLd8PkG${JlDyQ0T8q$RH%aS!8j4jq()>}HWD*0I*cUTy{;$J?i7if` zRI5_RN9L^5I9vdI+;#*+Fq(XU~!zvPRm) z)@LVR8|i&0Yy|R;O(mcV7L$;>5`1X&g3#h-i^)#08%{uRd42o@y0Mr`(K8j&>_Dc< zP}rBku+s&wXckB$k%1Z`t->qRXy%!a6n=eAOP0TIM4i~Q@q-LYx6p0tBslo;W3N)3 z!K-A3bkF+7hfQB;$Qt+We#?ksXZaIDdO-dB1BI|%;<1%+*9*BEPH>72^KJV24KV* z_I{rq=Q{#pcXKjw0{_wzA3|64W3zu*iyicHN~jWyj$T5GD`kP^7@i;9F!sBm>fQ9L z>+}L3V;HRyZP=oTE8uOuH&NkH6k8xOH8Zig$$CGO0srF_2ajpnporP&;=XvrF^jAU z9f75?qBFlutGRt9S|0CK>EvJsGsEofEaJkhREJD2_+Mu`m5WV_(v&p0kxCEB!D(F{ zFp_ZjljA{Hw@S^^>XoH}_%-#^;ERjIPNN`49i?M zJUn+tt`u#K7e5D5|raPpZmi*Vcz@7Z>#|& zZomj6dhJ%)91C{FXJZ|ATrOw%5%8T7ZORLFXM$s9prcKi5|iA6vG4Jv@|;?qOmduc^;Em32FpH!B<}leHY1>a`$#ImK_U z;lhEdQ}0nv)fzSSF>Gg2^ZX~@x0eq8z}!9dbDXOM*DAbpZJ=)7la9X*J-Ku}(w)qd z&N@{;*#yBD1z`pO>|&ICuE<0#{TB3uHA{r{L+N#;xas^OalqFKaeiYD*(vF=(066jUaY-T5k8_BsEU1{FyYjm3>Dhc_-gtasO=4=brjYLNKt&u1^l9N%3FM?0A0t zBY!#GSU_c1-T5ie(%R}w_gwSYlVJTK;X$@@a)ej2H=y?O2dV@#gyXG7Ow>I=@+mQNkqnW1HQ3O8 z7x-c_%kh^@Yvg+E_R|q=8&uhVc!Sh%O6Ih|mOE&YLKVF~f0Cz)XF`||jF*|x(i8%O zCgsPC%NL<0A*nk~2u*4S6cR?r&5Yf(a2rSiBdoL4l|UpgHzr43f83swx4Fg0EVPm9DWVL4RQhyaPsE3Vi~vmK^K{h+#XN_t!U`pvz#%YdrLWfSxH+p9c-40|4-> zhxH@|600Q!6Ca^{cWg~*PXU*AQSoHHMw@s4MJ%S5LjKJ3WQV*r%c&mdN;iM2vp-tn z{*&q10t;%MqtoA)ZeCgE@Q+wD&+!93GsQ!h4+UM40{l9$f7)@F zQB`4w@bh0+*)Vd)L=7z1>XqFZq`_Y_18F44z>Td;+?*7j0c=>HmQ{M%_b0E>HDfAQo}(4KjwFj7si9fZ>gZ*h6IrHl{(4CRoP; zn+EqY`fdUb=8^{LL$TxlvuHn1uF6B7@7EHyORkjHu577Wiz~Lt_%McGB=y0}L9DTS z0+6h=P=V2W0oBgVH%KIpY>~0Az=tiNt zA1>emE4-?t<}!u6i?mT-53nz1LRNFPIJbRBZy>}U=di7QH?CQHZcW)2;-1co zV`2_>X6_hbo?{B_iU-_Uw2?y)j)V&}$H{McQl*GE0FL=#228uVzKPJ3W+fK(Ba|WF z$c-Ouh`J0D?`%KRclBQq+$K*dwisL(AdV&fQ3y$CjHL@xOe9a1h%{Kt+-__P$Om_0 z7KuMF&Ycd7V*0rL04EmsB_Pb+GixnPVsM|T57xvabzt&_8A$P zLq;X&yM^JY6Ql=HO#``p9)hP5d*91L&PjEMv#)))y`P_gepP zH~sy%#IXL_?LDAIz)(KV@pV* zc82%3+41^~pn@wxI!;dD*EY6n_Ma8Ykd+zlb zp)ZHr6vpSE$`bnd)5vY??S9IdCy3!Vm#|lA1RjhrB20#pUyXh1vp4w zYCsEc7P{ABOo}#@d}GM{0_xJ>G&bXi7BQW<$%)Yd!o$_)W*jaFqrb=fk>0=2IMH)% zCSdt3dw2mlBWBx3=ehd|{`3HQc8WB+K=B`p5#Uz!Ph*^TJD7M*iTkTDQul#&oa=}| z8KQ`%7-<7%&!oFyb&b|BqM7g{j?G*#0Z(GjtaM=IhyBGEMT7MdC65)h1WwQ!ti$PeP)Ry=ftFtY{Q<9C zl!LG3n*-C<-u&s=$7pm%o#$5sF1e>D3~tW?FI|P)3GJ;~9eFijIe#(6*qm1khE+!W zVa49OBP?i47k&|7P#=iJ!7Fn?IUB#P4lrB&>zscEXC66xS;WDu}_0@D5eEqQ@cvjm?65JXSeV>+) z#NQ)|THsaNIzYgx%_DSaj+28nh&MkOxsLe(VXTS#+s6D%;J#M*;=zDd^Mj z8XFFlV<cN7-6U+{mKFDoCLR zj*_IaVKZ)kD80*UWq7To6O_dR?=%q%rT_9*!G2jodU?9i{JaOQXu9fV?|#-W2xe(# z(wTUU)%p=otyqqVFGx#mj{7rjR`@HgF8-Qg%v5Mgf(h4I}L#kyn>PC=Gi*r^RXNQl!I6NfabP^}t74F<48b3g6llYq$^e$4u zO1&g&N_V?#nLGC@klylD-RpBqrTI|4t={kSJA^{Ux^_2;KsnfcASYwH>krt`oC*@ZX&M+x0L7 z8u^N~bAWN}fkv!-zb-uL5d50}_%~GP{WbKj=bZbm`I^l=%I3fSGIvS>GIEa`xK+?9 za^UqiZ!pLWQzhh-$eo&@_d87@c!o#8eJf=RTN>u{ykY_7eXXW(k&W(RP1<;N&HOS@ zl+Ia>gonp_%6caSt+1(MkUN3N+>Iv6YcwOJQyj3pZNgO-VP#+8xQTx)#k zh5)rkXh3*5y#;@0NAo03*ZX25%?Z|DvXSkpdbIi<*|@=wVeX*py0+=K_+MnBF7Nd} zvhllLocH7mNoE00Si$vUZ#9&x{T(SQd`*{FMoq6^SYO{qqAV)_CM$YdAzT`bP8~|d zM$VjGrJaW$$*o?z`**>23pzP8fSdL{Hy5e(!WE2BE6s8wWaxcx!mp9ygeB_>ZIyP}bhcgyPiPMKKTFU}jj{U#^!iibxMmy9heyP-y> zH*w?(Ob(Ru+b0;yzEe_A%A1!0 z8?ct@^YZY2{#q+HDtpl8)G4$*biCru8AFX~Q&jm$D8Z0hp{~rvj-mx;t z5t7oES!%f=p35?fUDq#@FGWla;|RBAsXcQlJ0YyhgABS^=UFj7Cpl5Nd)@^m``Pjy zwj@4DUkF8`fjbw7W|Y89Of^SiN6xlR5aTL%6iB>;RnQpaNx!y=CX?aW_rutBfm3R* z6Q_8G4}+C-XFhen5|{{BC-u-0SPp?<>|~7xyNJZxD6?zXATd?Q3K)kzuowo(&Hc~M z`R?s)uk2Ufx94aw4$TjK`@D2%2C;E`AwF+&J|OuE<|vE1i>=g1E8uvL>)2FWYv5od z;~?4J{WeRy=-qU`rN<)o66~7Y%nof(yCTx(|8jxFQZ#?Lz**HnVIy;%vMO9ij9Gmz%!xV4y9yR!Q&3aRYtt6=V2Kw#60PiC@Fee9F! z+p`K0e3XcHnnJ0&SdKy>w+^8^uxf!?`8}b`;oh!PHnOeDH8^$B^R>63v?0BuCu0|; zI0)G}%3@Xj_@@+YA4ZK^PrVmZ56;QjH__sQPi;^NBpg<${l@%P;4^Tb>3 z=X+`{0y&@{>1FPq)8NDLI@kO2)_&_8_M4o4{Uec!1725qX0&)=D3+U?BP+ITU?!3D zV=#FWjbd@`)-S;ER0>?Vye_SbP65D&zQ2LJWQyi>WTQnJyS54ebRAH2=xQAx^3t(M z>`~TO$~@+WF(+cj>rNGXf@>I6o!?u@Py!ah?vb{dzQs}tJzb;`KG$`+vhbD(&+HU& zdn$qb!(0W5!hA{2HaRuRzYW^Qtq3>lJE z#cD$MQ?U1aS)ZSRikqDME09BX%2^rL+pnebV}*QSq{uzid}qM7edZVVlrG$sAd)lY z!U%%f1#lf{biMKg)!JU^B3gN_7}^Oi*=0~OFH{U1;#~ft(b9RNEgrCON>%~@rmECS zeZC?b$qh7l(INDQB#tE1bI#X- zoh`mm&WlA?xe%w$MqT>)_b*=caNBZ|x*}Lt#1_Db1`>-{kry^w^nDb=*-mZ^Q29#~ zgXDYe`ego8UPpD;67cI4Tg)3yLuV#SW()LH!VG?r$Ph1=%&EY;&rMX${M$2}-12{c zYhP7*=?jv~wiGtl-y6~DbAbN`T+_2j?KyMOJzas(XE^S&t z=6X7z9`*AOdqnG(vNNqPmZ(Eqm^GIKm2iNn%V*5T(UVMPxIwUT&@kR#7-&VZH*`S; zaj>opKW(5FvDxfU>Edwf=I&=Y8wx(HOmNA3gh7;`$(CG41h>P#jdr)cn3~A zEqN5&pEbobuS5irL6?0NBFm>~o{cE@TD+B5+Q^U|C}*CwH<8JmSLb`$(sp(){|8)C z7S*67ZNy>wEYPbdvCK!okCl(T2hscj*CHJj61S8)c9xrPXEA+UXzIs_#lFC`d010v zb*%2q+B&-qLjVVyPX+K_aZQ(XH9jucXLrJ;9K!1}=W@(Ulnd(Q#JY}!FA^%HL*=t- zpIh7{l?h$ds=vMsh*;F5^S;8YS-iG0jt)OOg1J|kd|!v*N=3UzCKGog7Pj~3{31Z_ zFSu5Bb^Y-XO2IX%umFYwo-koJr7qWsTW4n>f$Rkk^9=rwT+L@q3><}xjZt3UNen+X zE35tWvy)#x%!6lSXncAQ$9La&&jLgip?MjAWC&9B3R@lgjpa9$1T#hpwLyf!@`^cn2dm(L_++A|D6%$%JyTF~&I5lc&p z2DQ$*bWdvNI&I3DTz16;QNq+8tDEX#urUB?Zm8uzOe7FDqKH>-l7ZCrVq zSLGX0PCp*q+M!z+X)AUQn-Q^tw8BXZi8JorDaWJh)0$EpBH=ehj!;SuEi(pc7cZYd zmcCl#bVpDmjb&o?$D3xDR?8#iMY*k2)LYy`C9i_@fm3tmlfwsz5p9y_WMo;Tr$+%6 zEs+w}fJ*w10Tf_4@pN>1v>*B1N}roM6s6)^y$j-#q%t*5Lt%;Sh}C}6Ab6$n69U3N zW;3{YEiC8HpnO=k`-7;A?Zr**%v=(~C&1=R7ZIdIyRi7ar$WJLh0ofp+RGGv)+?_x zW6-vn3N&PnSm924+}4^~3ahwz-g^Mb_3y3KvmK8)Xr4TzH0*-To-th1u4n|#bg^BoRae;D1{Dx|iDuz7$m^JA(p%u2UiA zKmOXF|K87EQH}H2_zGi~hh1K}Lf&kTvuR8g)g%ojT_(wQ1E;vCnP=f0HnA5^HWve* z#!T!Wv@e4$-+UyhqT&L6b|0%mB6N-}=vt|?f&L>;gs3PJ_z)phwE1)$5;`C2l%(J) z6lJL^<-ZrM@5}p7(6W+YRqk*Ui*WkIcusJ z`grrB9L3n-b9)6L^UGWF`0K5~{PWf}GA<>Stj=H1P~68<$7Ik8F~+}YT+^#W zcE^Cyp*x=p85~9{U!M})$c8io&d-XD*2&1D9QFNr$}2IP5hgj3?&6Z!p}4&oxwaCp z%BY@%j}%6Z*PrGAfXxussG`-cxr@q7a`>fNKna#H&-tBp@b~hQ`i!lOs-KtQT`;}Y zL$LG_Sws`!fJ$FGQ~>Qgx^cFn@-~w4kCO!hw|mA#gONDDm-&}t2Jf9F$b7HJY3?_V z7pfcYIersQ3mf{M$5O+?nz`LkY%bs5-IU+*AY)WZFAt^30j6LkXI?UKmMBG+v8R_5 zl8iD=SJEe|MxLBhi;v$cYGoD#X`e55I-mMY=bG&vES8 zW7TWm^5&V*<~iuen(@k6IPI^`gJ8SwADbmkHHKeE50A2<6IJH8dz-}Y#i0v?i^GZX z#(BhBB}GXp1J=zIwAf*W67PO@e(&gcp1Rs$!4A0m zB-3lSPKnue^3km>BPn9UKa8`8eXEmSIZ4d*`A%z2(FAT82$lV(`yi5yA)e z`{6{FeOAwF4^)Xy4yF>U>2ZrceQkI4<+jtc12lbBb>_6uki}E%8 zSe#G34o4py)uqyTy7Kve%3FJ6_H{KQ#B*_P$Zg=vaq50~Yc^d6KBOy9|KqI*lAgpt z7e8ir{qxp@2Zw#$NDCU4{&{O8%*_2fW~bdxr1E#mIy3=UU*1|Vr_NgrIIlP0^=xSF zRtAWMhl~5usETgj)x5ZIDsV95=H#ZQOVA$c;q}Rhb(*O%*ezuzP{?#1{4%=%?+VQ{Is#8CN#<_1fu<`@M)k6Y}T~C0c134TZ`UvHA*G z$YMa)g#qPQ5BhIn5azbR5o?`lgP=L$9INGog-C0zmnPX#i{PSz>@Wp0ZWJN!f9$XA zJBv3S1R3ZQ6PBX@I*)7ZMB9Iqs>^PJHQE|{g`5zqz3B45wQzob3!4!_31IR>{?7b;>^8zvOBho@gSqJFAGb!4 zOJ94yo3obTI7P>;`&JiY$#+RU)Ohw)%9Y_5NB(KzsR8(O?;IP9^6WGud37*Fkqu_h zu+x?GP~OZ`+@;?kZJzzSiiZVIE>s`k_SK1gW3lKNDLCXt29BxV%X;;1LfwmPTCHQ( zfPGZV9J4}K)*us0inwfSj!Pfiizolm*hGCf#zxM-kSc13)DhI&2YCf;Sp-V7c?y(B zYnZUbA^~JFz(2(*g+s!>*`U1+Po$@H)V#Uzq$T*2FrFhlRhXpBPQtn;tFW|QqhOap z*l8iJuk(6Hdk7MGNh6{MiO|*(8^s3aMI>5{ar9tuFuY^OUFuBm@s4NUoHiyYEP5KV zGgY|G^4lp#cSu<}jVW`Hjg+&42VRqFkyTa8k^x|c@{&Y3h9cXB{j|ATI-l+phC_5; z;V+Td!(kz6!{Bxm$&u^yc6W73j4kssvPz)j@|NjiHl&OlOJIGUQH|VZ zy{`!C2%S{^7foj!RW}nX@Lr^aQVJAzcXxL$?(XjH5{edgF7EE`l;T#bxLa{|=RUr7 z-b>EeSv$!e$!>NhGr#%HF#Am}jxL5Mr3`wPMq`{FEkcJLE5F21jXBuoT_?;mKNca* zUgyqD7Oq(p{2ni|C8f2)IaZf3*mNrR34ABLVhGawl_rJx+v7B=pO{;;mDER%aV{s+ zMZ4>hOkON38RJ-x;EG%qcPQ2u+7h(ozx=^++{VuX(?FsjF&g&YOeMwE{~Sap~I{{ zXG0l&$5?blc`0d%@HQ9yWQ0#{`VZMgwuPLN>ilk|AJS)k;^ao$_Ks`=Gm-xYQl*7{ zIzTwFZ8Wb}{SVnj4zS4zXXC^mQsgvE}r*KsITvm;E&TPy|Lwd3tKFjkb?l2YLRf_f0{fk;M8Sd5!)abeW zmI@0q@N!9DQFdp}K}|CiQ-MvBz_{)p+-&?Mx6+Y|p`*FP@!nWe}{D$%if z+ULH4pOfMJy>s>!1y2(SLP+(T)?P?OG%~4AvFqS3J6;d+_-W z5EWv9b$ICT4jYfOkgzuim@E)P3z`Ni27;nNY2fuhkSWLmEE)s~1bmMJ=+QOvM&ZzG zwQGm!v92zvHGB8*V6*VkwvDsy=*elZ_VK}`4F{!|$^4nLDRf@xy#x8KDvSdcX%*g9 z{f;`Gk4L&KvxCiC)v#U8X+#(>@_42gmU2V!XABwVO=`h%4WJ>y~Ypf{1$Nu!3tus88H2~R#o z8gKQDZ)0W{*Ei;b4EVk&MI`ah#2v=dzy5(y(_s*@>xJ-hpMmd@!QuU>TU}oSTf(Hr z$#b2%%0q>k-n~2Z@+oexRdP;fun2hkLMy{45H+bg%w&6wXP&66MYyuQrm?q}VuaE5 znBWUwf;fKuF_+2yt`d;{^=vadgh52A==;z0y2K9WAsbkMO85hiK*g>;)hMIJd8k%*k3gWoS(%v(cEmz9J6PF2RSIziBr>4|V-nE3= z)Ytfx=iop$s<@Pm_*V+Tl&VQ{S;striX^8-;)jn&pZ4Kws%VWaBJ+{4CY6QNwX&F@ z2J=uC;4@z-MtKProIm2An5T8~RJGtY=|sJ3=0(^l>K6mc^)*#bw+u5pvbRSrP?4A-0BgyR8w8e4-O<0Q0e_V zaaJmm&Wk~)l4s{Qw^bZM)NpJ(^n_B}u{_)8!CD>+jV8dPjyD*UwBPv<4Mb>AR-I6H zaY|`EeI^6i*4$60#0ROTT4<|8?~jjf{=r)w(w}PvjHY-@f8wKGf*|i)6{i%M9{3hH4SRzE+HeM}|%{A}p zaaiaU8{_jI>%Nl~Fp(0ADXhn780S@$fEvdR_H-cmFN*h}x_V-{ReO$o@@L5gngbeY7HKw^|nuBZk zBkH8#Ha4DJP{AoFlN#dx)zVCE0{?Zs_@cd-8^X@_-Wp`X7*tSo_TF_@T`;qtDxD}3 zqU_#a$4&Zx)Ti=X2yf={=KhT=Z&d@bVLCxdagVtq`?{eD@f#heIVhZhzaWC<>LWXh z5%~Ik5D0jFfcQ8%Dn4yIzfZB}>x5qkef=CE7ZsoGkqF^QsfcJA`uE<@I3uKeykc!+HJi2 zYk<(U%@smwsTQ=E^N&(1`>X!71UY4=yDinC?UBcARt6tLN0d+_p&LPZ{P-DSvuDVU z#KwVcbh}vDy~f54cw&A!-`>=F>F*^KJ@i-WVv;i6i_($Ik z8N9G0PH>2xL$EDHTO5|6&Ay6|YY9ab*K0L@a{_U($zVnR@XY z#-Lq4FZ_1F8-|*5G9<;t8d6GO5Q4oZlBI>&Ln`73hZ#Od{h7=`NKMdpt*WDQg`J*G za^wSPTiej%UHwc(hEacyj$9Pr(m?+on^JWD~it6>k)m5J9Uc6@{WQTmAf?Q`m53- ztkKe+g~AunP#9L~&~WK5lk?aK(2q{WocpB}RwP7-b}vvlQON!&)atZ~)H z41Y5E`n@h0_&#N-^0za{J%n&uVvs;_hL!nQDG-@#*quJncVJ`onp7Lx{_H{d)kuv?t|N>YmBhH|Oc$=P8q%ny>XWT-`!d^$4Rlmf zuS^f1LT+cgwkSkrkp{;844xqii+Q1H@v#4N-d~7~k%P1xw_NeAs~#5@xZPeJlW8BX zsBuJkD*EW$JZN8yr4E4)5Ig-4Hk3!+2Ned`CK7}X(g24?f(QvHnLZ)yw*G)q$W+%2 zWFzI@cl{emSH$8(%}U32n*tt;1f_tk!Fo|3A`my&|6O3D)Vz&;6L4UzS1n#r>J-Np z-klHk9RoK;fjB@&;NvI|GwfEMPtGxzI2we7zECoGy4$@V%PTo;51U%bTwQPu*n;Jw zK^z~uEp^Tfw80V4AmVTMf_~drG+Q|<>`LYH3TTglP~fg;5Fuy>y!L(-&~GhL08)e~wG;@|W>Sxh0|<_I&+PL||heDOAV`{KQ|9PLZgRZFcl zOrf%`F#XzPNH+Yflrxrb1*TKS3~mG+!9N$Q6bm9FKZsiQSIBueN0(f`7<-z?xqCV9 ztLYZtqT2;Fo{tQNA-@v$O~C1~AW@(sW!&%Vx9H?zpuSW5qMliZaBTmn12I>v1nPOS z30@Z7am{rhpXBW31~S=H(t~7PzgwF9CLF3Q_P6v9yg&HteqBr;Zub}*2gQ1+%MyCR zc%<^>C_;=}yPl?re*>`FFClKfpF2_7^?9ars`$SdxK`*0Ym_-Hy!2q^9&G}-!fVx> zTo`{ayok&ZN?RTd;j z7}jRF&8?Z*dsasH?b{Z$HR6C=V<6a&CCBEGX#8bYZ>&Ijjux1p=gH^Exz26in*9-C zs2?tx9!!?cigEbW&|C(mgs;@@UJBY3!?Lc>s`dl+$L{-Gu7{T;-Xgf+r*TcK>?_LB z;173|sbI=NZcD8avwt_nA@{$*&No+9Di0aJUoV-|O{FoZCT+8~z$O4$EK`|4rb;>n zet^spZa*^FJV)``*`!1@ykB!G#o2dYs$Owpk?p{q7;A)gpk|Z5!4oDVduw(_euTk3PaP6O>4;;`Whg1#K7n+c`S$HWj`RJkRys%|nM z)#B4kpr+m?^g_kxXs8Y(nVK6y35 zO|gJLd`VUN)O+wgZARM=@>*SP=1V$4wErcGPA6vxqlsF2}owPSCl{@-+CN!_e*Fb&Ai> zITz2a>)GNlXQn~dhT^0Vyu|v7v*q;8oJW6myV7tArf<&Gplgv|h+nh@)7cvCaCB2+ zK|07_45RkrHQ!kZ&8FdRizsm5q@i&*&E^}6V@q64AnQ}AD1Jw->ORR^jHH#G5YWQp zt7hAqUo$3Rn0_ji^@YlL_Ay@P*=Atz67MRBXj;0eYvyy(Xlp)SeuKA3N>@wDr`GTN zfs?H~!Jp;sy84apl45uNVQtV++|7`a%&%-^8Ra*bgFgzZa;Y_cTV0^>9Dd5>TZl4X zXm|AT2Li$0`TCPE^456c7|TMQ%IBfxvIn|TT-me*$Z3haMr*z>h*o5h0ba5ZXtsqh z8>N{jR$KYaaVTZAq$yhI(^T!mCwj@sX-~M$fei}V!WIQ%C0q*SKg>nWc`lQ4fZD1i zqF(~>YX9>gCWLv00Ia`7_`YJfC-8MsjDfU5Hs6pTPMDKJ_z{Rd&X68+Jg$6K?|^?Th?)=u5_|#W+Sdw$ zV>-x`-P~Dsuf*BkBZFaTZXRw5;G$2l#-sKLNgcA$HrJirGgtYq4YB3eTj3huk~-46 zz{z7?&O@$;F~o~^1mi+S#E-dYdVDW`j4o_ zKDFNt-5!aKKhej>{3e&LEDlAGfKDH*}V zCtm!bm?_7zof?Z0M>Z!ei!y!s%Ln>AtE&<`t4|Eyy_Um&dRMPA+cXZRuw|1)g}P$w znjy|}fsXf?dx+P5;Frb*0=3w*ihjzEhR{#JIoWrF@r7*5t}puwNWU0X0D>DNy$Z^$khlfA9SNuQ~Wjj$cRL4L^SXqInZCg{xQy!#cb=i zkRh&^>&xrj;WZzaO@<`#q1?ZRbNJ-rSOC76)f)fN`pt(U;(tYCW}?(1w+Yhtg5I|d z^vNKOGowky-3wTy!iqH6x$%kJ~qb6g&}#j$b})Y4`u^#*gHW!CGis5 z%53ULR5;&fGfF09I)NiqWHq^_C5fkbZ--7`PuCB#WlCS!T=ahGO=qp3nNU?^OCG%& zs^2TxdtkjP*wjodF!yWWZBx$TiQBp5mt|$XiX$MBQ+1c%x0s2}~ZHmT_q9{6(HbByhf&vjpa3cRld0`Z4K6 zqB7TYzS&LdTU!RdXjI7_E`!k!yl^r*deA+@iT@?y7*+<8j+g|b85mf3Q0*wjRyzx*gIU2$a?ANWST z4U#av`1Iv106+l((6I^e6M|`T+UucD=|2AXdBpQ26$RQH2AhfWzf$IVGI;s*zp8#9 z0Q)kJiIk)C1@QoRTo360nGlyJm~-9#^zQ0?W=mX(UJho9{Ojb^vL*jv@4Rx)pKn1n z9XETCSDgG^ZBAA+LM{U@4n2z%q)?~9sWM{g<&Pa%Xy3AdbJm@ry3YQ=o-&#ZWmIEY z*+VL`D2`e>by);NMh6n(vc8M{7PSZ1jcbx^%hcM?kN;e~BbAWBM@y-$E0NP+vK(ev z@eEy({6f2tDc77QTR%ZpKi|}WZs*G~#F4;Wd=A47K0G@Gio5AGM_tSVQ#s6G13JTl z#7U-BZT3E0MNMvX%8zjK;0z-zMO|nXt7dIAiLk=;1#vQ` z1;D^F3UV4XqfyXIf^6sq-kIxPQA5hn?~pCQjC zg0Fcq5a9fxqUIOPBLoSl`^ozPvN3S&^bFzLz6%4;J73-8-*7hG^xAI_(#NJpob0*7 zN09dSDGwU5XM`}9_x}!76aj&y1 zf!`BNL3D=HvhsRvpQS@ou4uld&Ic-2SN}2bQ(`+aaublIhI%NNq0|+yl8xCJ3zp{Q zfH=|ACq*ZR7VaTJ>izebjhM5Y3RKyx;f6~Ukv%~G63s$(Q93G)Z*sbaPDoZv6^-dF!qy1~}pMzV? z?fE%xKZtvZ+%NrHS%O#68vN9J)uw z03P!H5)6Lqe6TI8Rsj~Zw-MJ?BE-`7SD7z)gFzi@fdht5D{#aw+fYnwWS94Z-BW~I z1n8*q!lcNzhIz^!|L&#&+TdjmWrP_Gtob94dRFQ_!E2xuh4eHw%dGmDORf-L)&8s7 z8Lb@gawE(UpBb-rCGMSA7(EU%NKRszI&lpeM|nMCH7TyAcIKsS|IK41{E~u1s1U{_ zP;FCuy=za{?xoIFRp+0SlMkC*9O-QL*W>&5isr_M1Lo)aMX@J$)Rs-o=TWdW(Q{k&`HxKFfIJoOwT=ea>%zx0Q8Ew&i1M z)yrP#-o2MKoYfG*6wfcMHn70u76a#?xgpEz%h$A%B)xh!&o94RG@}xNe@Kh0xx2YW z3}vdbsc8#ewtBSMOOPXke>e@JWCFHhxOo4D74Q@!|7jpt;f}195O8m1UuK~r)|(XB zze(pq+LdJeGdaJX`?P|a*xT*IwQFFc>eDT&RJQ83K=Az&+A?cQxS$|Km|f+99-eOZ zLLhX4pn!#&&JBE7v{2c|9j)bS+3@X!`rn7c?S9U}kOwCZkDocyC%6WdKLLPPpkvQ{ zcLN?pgHF0tL+wT5NiDi8-~NJZW=~=!>U_%vE?@)YI+8qANrkY{~t-vk^a8&o;7eB%$1d8|V~k&w;x_5z^Z(@%xV2Cr6)A=tMK_fg~s@ zu_oT13KG^)ZIAzI`8ZwwH5K^g^?Ud>@KCB~`Lsy%^UqXj`VwjmG!;(SL|{_07aL1h zH09l`;zt}#IZeyNefTKouk@s%K1Y}QZujiBx6ua&(aswV z1~#sY+HfE8!PZ&$#Yzs;Rk-*2IJB{RW$BN@n$FKs|JL>m?#uQGAI@-3L+=X2>SFP! z(^-zEY#oCKDnMQkKmbB6lYdpJ2X?-sb}V*h*~_c+lGQ#7ObXUlBAC|F>*6?Pa$8%Z z&d}JIz1=ut(d{adxeAx4stFow#fR(eh?c^InieQ7F?a#TtGxF9Zr|?y^>$>04SB7o zK?;4S>F^Xddte-Mz=eaJQ3)nQm^OSuauYTRQ7jX&T}-wEs(8iz$W;ZmW>S)jriAjK zUU5r;nlF=EfVq|d9zo=W8x(u`JN>N#t=IvyDmi&zz z!Y*cnsHB;riKdP@C0kW5&~J*!tW{+3bL8(Na-!Pv7iO(T*7v$Cmb*v%(6RR-`{Zv^ zQQ7%DE^FZD2##@mXlms$=6e#lgv6{RDy!bsK}=!u|1HE6$E1cM?-e@CTFc?>U$;~5 zns5e|9|ZAbJIs;gnIZ~ozU+n6-dqe|>%5`MR0#izyrhwC?lc}zB?CVv-{FPNMP;@j znsW8Ab8$KEa%~)^6qAU&ozHQ0d^!gJfy|dfFy|K7$Dw!}vi!O?ZR&BKA^E6qz7cHj zCQI3kFZX6~H8%MvQ7{b>3f_?QGgyCib~wkq9RN<+fd?eZ!V84XM~Cl&$;GWpI787! zj$J705yVjTq!}>`$A^fkvT<5~$m_cC_$JuaT<qy-j!eNn2|HUzdf<4MQyI*$*V~O6INm7DL&zt58Q~%iV=dx$LRcH8(>r6 z8mvLt-4G{HXoPC>@gRG&XPiAa@y$$n_4BrNLH<<@sO%x|Gm|5pkaAZDqm z((X4CcjQUpR*6LC^Gb7YJqu*cg*HKYB*ugi*JjV1VO7O-`iKDS-Z`Pwwi)&4bX-;C zwJ&Eb>AMR|rGFAk%*)l&1u7+v1}&hXo7+>gZ8;r@f6wS&Oz-6M!fsaewL(Y59*$V%reY2E z!+6kx4~|K}<$WfKuSy!mn|7McP_Q+YJG9HOyL>axco$!y-g>`UuXyjwAXLOJs73cDJfsCpW8{!<6dbsBThDQ>GtH8dn4T_wgQHvql zcT5EgI?okRk(Un!utyc0rtmKko02fQ{>8-I2F<4;zU`}3e#K(H@o>bqpOQlOjD%H; z#ddCZXpDgEYrQ%InXqHnARe0V*T`nXKdA)j`qIiyEi#Ezwsib zyd!RxlOy$a@Ug6WZTjUUn6MT9$sWV;lu6~HokhlW#w4Z~Z}V=UZsK}_UoPr{<3d8$ zJAA_|PkmquHa7g@cgMx&THSEXdhNOV{mUbuWsur{CEn}evc$VHdj|%A)@;-v-8gDK z8ZQ4X{R)j1YVL2&pGDoZWM~u_0+xzk8;VKem(tzxEJ5`<|EArYC6y)H2Du#-%>Z>) z*L}4NSIy+hwA4_ZbsGIKPP6+X;V60go2IKd81u+Nwr++!9uK1#E|xZ(J=QLa;C*hO zXMO;N_H*(kz**e4k~rg2Pu*=i*}Xe@j zJ)dlmrd35It<(%|^tsmd^tX9xIQwwSVe+(@(jz%WfnO;xn!&QvuDJS6D@UKe1jQf) zlokok-*i58ioa+w%<|EbuRekOi$U5@=W*cWVo=(sS~bScQ55Z$f-+|UQ|rf~tt>wrx}~@M2|5aQ)221o3lFN4B+egq z5Am2IB{6b9}91|%>nnZg&cn7 zkd$fC9JO7rGiphBy*I8x;9vOyzi74hEw=OAEi0MUf&d}U2u{oeYBW@f5)7zi3kqnH zmp6FLflS2jpK%Z)?(s5bwcPFHY|d$Rm%pG%XHW2j$-D*tTh{zY5iSfYosk6?)=5ZDT-%dDM%Ns(W zd_=9+GRUIfJMCggn8oPQSAetUzkhewUf`%Q>+YB>bc=pC9g)tF`uZ*V0HwFX0y3cT(df*KZ)Eu3N z_@2h_Enbf!I3?+baj}IKi=fu0Q9WWPv5kXsUhrmBSWhE|__WmBQ*?QnDB|RLIx?Ra z-@;R1vBCUJ0mGgSvVU>0)z|m^ZSu7y>?P-Yi5&kzxY;8257G(vFQ-7RpR9b|VsSox z?pc1xp?fiW6s*a~&h0LueU|LvGKC~*6VwBtCpik-&-=G3u_uJuZ>GZ#EAs?mNQuq+ zB4=(oVINWo*ik_&TzdAb6?Nb^G{)y)GkDh!d-jqo;5Y~a$HNS-+uw6F0;2B|QmEne z^1kS&45Td!AY>mpET;;c|CZ6x@!SaF#xmU{*L~5r3?LEuyLmq3nnJqnFD@#2-h418 zC2b*Y@6nKE9Ae)8o;~dWrC7dM{xZ$$MJvl$X|ulX#wXEIbS)fZQJ zF{Df3rh~QRyy+VtYZ!<-13NLPI+R)0rhVz9uMb{W$F-*wv%=ceE#KR5XWc0OQS9$Z z9@q1k?O(CFVg5`ln&0h>QIMH*zB|^G)J6<@vZj=Nj(|hdi)?i8t`o9ZUVEZA52}oW zD#P#@;4iwK90uxCugOsw2`Zqgg5N(b9%RkWw6nB20!b^o-&CxiK2 zMC31ioSA4{4}H=jUKn)2;biL3on*nT-A~tY0H=1OJykE=7^;kaf*J8sgR|TrZF*sD zNYD<#AN+(L*y2EqDv6@fuI57Mo;7Dl0#&w)6e6R@+9rjyPEJbRxp%O31ns=~!UkC1 zi#IN)Vj%IFcF;eF25f4G&?~4zfeH^nq^wS>qj{b&UNiMLc26i9IN8TsImTZ&#-FJG zHXN|pl#Qrj=Q`)ANrihw2Jl_04A(iVvc~u6%Bp zp+O%DAEuXg^VW;Qtq<2a)TR+GLoPw(<>;Anas(f5;WRpf>&yV-C7&qMY+*CwaRz~| z$3xt)Fl+KTrwHw(9)E_o8H4{nAJbFUhajo=I>RT>+e7h^1akr;6*vB=mXOS=Sc@ICO*-&5$kCAi7_z=7HBKNbLaWal z`*rd(l&yks?grR%XrxWslBfLz{>-M)We$g-BdI4NS~QTy5fU#-4$oy35gDqGdBcb_ z=VM{~Y=Pw;AAN>`FP|K_jm=RBA2|0w-Jy}2`{u#Y zHecd7Jgxh;+CGq<=9>(`)K3_aY}|t{a-HJYFsV@R`85KVRuqLK;GFe@cl_haq{9~0 z!(nLV%cUf3?DEbfVxRFq+&zsZY{ekV=385UeYj~GRBRWkLYy`Y(E-u!7u78B$uRdU6s$jr(XE(qZRjy+8Ya`DI-Isfiy}nZ zs-^Q6<;EY=7fOL|-nT2YfSWbJbu2oxgvDNxf|Ry_(6aiLCHuMj%5IRz3HsJ1dbs;< zu11i{Hg~arpnnM_P||eoF9|H;~CJJ|te;7-naD^EtA2rYzC z%#00w-^LZbF*8v|Y^s*nIGB{`Vmp%sUtE)81S~@ljYZ*=-h4)bHKa~a2^&pPb=1v% ze5gei;n5_o1%-}mt3AgspuoCC-&i;H!F1-+C_;@C#loNlkrq)Si5rwNeN+GX{S{M= zmLRS6#w<^hptj8qV1b-LO$$;&x9DrnL*sm{YN=d+ zW)t;OoOnGQIGn<&|GS7#fYWHgTh%JZquzep&mRl6_QFQzC>-yG$dHW+04>j;3x^7aStc7)^+UkW6JO-U_T<*JM;Ot~y%l-;ij4l55lwOy0N-`0hg!_mO+A<_9VI~AaEyQ-Gx{>+mw%ljTEJTroz!G z9u1khCxSvocDoQmY(eY|QEkOCJG_O?pOKoifQb^LsJn>n^zjQht8UAYTltqS2P;vn4&Yxf}m@s7$0quO<|Kj+ioiE zN$GBm%jrE7`uQ=T%yz{yuVr9m!o8OQ!cG$ENH-LhXEHp6iN&HC{-wO{)(r;K^reTB zjp{gv4Z<1wXr%nP4L>y4-=%yKM$+?#DVnY80+5=cOOf7@N}=*foE`VGVfAm*@NuCq z(Vr6pOcxRBGT4~4`<50J7TQz%Pg|2rwrkTp5qE+v6gt-C56oE*9ZtpfJ?*bY#s14p z-w*H#>QLLk`!+t#O*|S78c{ERCFv7ngg+T?Er{GQKO2cybhVpLN!A?KoxGs1C6xRg z1Sl92dIV;(p)lf0bs#PslYb<4JjB69a*N`oJqW?}-T^*jyVOkD9Ib@xh&56vL6o4EP;}V%$Lf?E!L!>V=qL^N@>Hi023b{ zEi$JH*0MU2u9+L9$PXE>9IW}>^9aoKwTidtxO8SXncH=l8Tr~{8HZ|3OZk5dC~h`f z)M0)#ALrcB>=_UaJ?C0}&xpc4Q|n`!EQh^}jwvnTmU>_z(VJvy-b;Pm!B%&6fR^va zkNxGbd3nQ1J)89D3;ee};s%cV9$>GumY<&?7JAe1I+*1l&M0r{Yy$l`Gk*=Lky5h! z99wJr&yr^p64x@{QSoJJ_=^F|k9~|!Ggzwz!7Q3&KUmPj9LScXcK-H(sR-&t9N8l| z6fTNlw(mUAJ1=j4#7H3J*|E~EchLlgMtOpNKIwIE_&9lJCbVdR;AP(`MFHME%0Fng z{0H!J=iCPqbL@D^wTfXOmC+?Ob*q7E_}hDlQ9FT6D2~XWJ0duZke%Y+A49OA`%W=+ zmJB)ndLdRLWjhXgFH+KNx%?pGL&n=mQ4AKq=|qCr3eZ|(z1h4D#P>am3)1OBe4`lwq^M7$ zLD}`20aiJ7a4o0ZajWSFZC-fS=pM&qmcH-|sb)p(E|f#YLpZe3O1Hy z$l35Ocw0_?MC4g9s^r?-UF~JE>$EYPa<*Y?x)O+o(6`3Kq$1b6`p(i+Z9h+~!xCtc zPekE-p_h=GB71w=;3r%-0*?l%VQ+Xum?%2Rl33YTO`k1xCD&Y!ke$tUcY4N$RnJ*q zUm9c%nkv^pZz&XOdf@|(hAphSJPj6~D_Jl4w_Z4Hy*Dd$<0B(AN-n4<_yjKA`q~rw z%ipocjINanB@W7a90WAe>pYRfi4m?%N{<4x%MB;JSH|hVW>l&&2Z>$PmVx=d+=xYq z-W@z{iTwtHIxswVuq7NV%i0|;DMO~8Mr(-JmVV`jpt}q)UW@^x&%5{vc|t#V1^Umt zU>Vt_p)#&Yf*mk#i==N=zPbG|H?i2*SeL)G8UI#w=ujdvr?2f8_*3vpy3ho_GN0)` zXYVTc_+u6EH}Lul_Dyaq`1#olo+MnC!H2@yJRYH7(|TzRuRHjfj?s%Z_7AUnxQMie2big*hCs>%H^vyceZi%tcfc7aHN zTb3+cSq6E=35c&XuGfifdkn0ptmcY&M<=a;2UM+GLC1baFx}r?Z4|~xZ!h|>55etU zqwN+PHCfZ`SoAI73Wc|X);`;4+$>gt>1&$F!g^KgY$OA=D%k|*XV|7-4PuiH%$(>PipAoKJ9PF&}`9&`1&R#4MC&i*V+#iHii(U*By)o9VP z099GBP%r+3TCVZm4k^f=Ek7^TzSggYP}@z~@gJ~!5ZNNRDS6)A(}}*Jw_5r8EbQ~~ zABNm?q3ic1Z}Nct5(-ZlLLN3Plj6#^u)PEnq)msJ5ewmG+-6f=;W5rXUmCS!fQYGX z)4+Z<1ocy1!^lS}>R1YY*j6?n2o+6tVUf^_=X8#!nRct>7{V*08B)x8acRe;j`3)l zyn@v5`Lx0wA)_Sn$s$apeDiGB55Gy@DC^sSc3Axf z4vxed-+U|=1i#9wM=hf5OJy-OaCA3_6KIeU?m~{wq#uYxa?scF^|_Oat)H$!`{X(w z&(_y2_Q zX*IFA(!nTe2zV=wZQX$K#uz?n$x1SK9pV4hXlbXBklw@};Gf~ZHiayLzNC#U0*sz; z8kSwu@HVeUr|=19vvlknGRj_s)Ku+y?+i#FXq*?j51vt|FNG}OJ}xv}dpF+7?$NMX zCweSjakk((u$wW8uKX)p%QK$HaM=3&{Ctqbk1YvNlfoI7wXk6dDUuB`Sn|bPyQ+C8 zFVGN48Gz0>hf9JD>0-NPTz2WV0@4GloL|13H%t7yr}9@KBk)h~9Z6hsg)PB{Hnr{7 zcz_a1hwof#Hm@m7IZ6J#nE~bVd4mLasuAQTwGp%VXe8KFS!z&?K|6I?uW6hrdEJe*8+ouv+yRfJ;859)JVI zFg4-LDaj>dW$V*ILb#(sdc8PI1=j5W5u&Z%=Dmj^CP)43b@{2<_cs@ZmD(?GY!3(r zNU7^L{ewA2iJfHUh7vT#Gjd?ztW4#RJN;vyvr8vN7)fE}=r2Ex6Y!E5AzWNL5ANWg z6?h17X^O?aq&a0{siR8v#^>Y67S@ib-?xpV=3;=xsa$pqUqi5)VtNS~ZEE@IbSSV< z%5k`2=IEEPQ3=H(*%udLqQc$ur|e)En6Tr?)0d@xJ6umBykuHOnEN=PR1|#e$?hh& zVDe-kPkO_N>pmj^AK6Q6Jc=qi=l!B42;LTEe)K3>zofd>h8IlLFlY5Gl1?rpR_}g# zJ~)3zifRV{O<#H|aU9c96w&q}h)cH+)>yGA`13h|rjOXjy;`2l*&?Q~Ls&IH`g+9x zKk;6!pK0)pJI*Uy#-3g)cQsCsK#KVJ>Ah7vky;|i?x-^(kTUjT4 zaIbT=i%PF^1SLIe1xww}ilX>+9mSpQyW-HO-A$yuH6}ZxysT$5c>X?bh!5LNeU+8k z%X0ZKZ;*kHh;79J$NN?OZ)zF>^&%=UM|x#E)Y%G{x$pgfSVHxH<`lEn^(6{tp6TQY z+^|1R{fM73IcfZNd9g*1EpW=Pr3XJtetD;8*<+a^v*%Z>=BsnQ3eJf4(g`&VaB~?L zP8vxyVd}OTp65Mbfo;JQLSZp%SV?QqeX70^!Cc8%oA{&J6cw@7P>3di-$JHgIJ*|J z!bn$efi2qusPe?te1^W}YgvDLID{gwhRXf2+poPnhZ=BS(Smi0-(X59c45cByX!54`^GRiL-97o7+$af@1`-z$W~ecI8P-Bz&1_TzWv1&5bJazWGZ2sGC`iT}{W>r@`1%vl>6{0pLMxYwrthj~Au zZ8qbyo>FM`KuQ@R>F}sUoGmLU^OM~YGUI@y8gbBa8vI5}@?V~@RkIP>D+7;MZjb0M z=Zxo?z)z@QNWUsiRjf|(bTf~a{o!0TmAh<^fDJtmLDh8DG_Il$m z(=5jzMZ+FDIXrZ{5*uuejd&)TdnPhWjzF8eMh_~&l>JWOk+YcbT_#zpspXEND5Wp8 zj6M!!w1(NLI{{ur4pn>UE3$^TqwTRBx2k0tFfM?0-mHo$bXXYjRolGIvuu#eHm@c5 z@MD{CBwsHpssg`?JVrl?xcs6;Irr54KLvZm;Q8i(oL`gxRL$=k9$NM$3yad>iCYXA z;Lor2QJao(bst-;^CU$#Ue>Bv5Spa;W4fK>hrdlD?Ae*^ ztFx+wHf{wcM=nR3u6$mfV(M`3ChY<}s>c?xJ`iL_eJ;s&sysy=MZHY5xIMWdDYlrn zsf+t=lyJiAue)yIY!fFll2FNw?Ylrln7v6w{=C2WLQ<;QtP+4d&tnt#NH>j7T&x8fMgb^0fP?Lb5>n0s-y%oi7M&=z+e4Bk8M))WWg?BSfDs((?P@cbh`hNl=1l*LLy zeO?;=$w~@-qS_eSnMLO|nigSnXECI))2~$aiwEj2p=C5O`xjGS9ZJE%=MPzTHb&b& z^03bAl%*ZS5!`DxP;4T6X$6HzHWR0PC+>i=MS1aW9+K+%ON8v@U(Np0NI*Qf=^+u< zb<2}iLLHSd1OLg9v-q1wSHRLLpZ zs$%pJ(;%_@ti|rn6CRm`e6JC@s7=+}Te2tbwP@RQ;0O6v|!q zerrK;{)wJ-R>u$W7SBryE@#rk4n(7W)NGsx4QjqORgE%hGNJ_HdJvPv+k$|5d}ng5 z-cS)|W-oF1b$IT5qv7S;fR~#-+;mS^%E{3Zn_C+i?>2oeN{rHyaVbq7|6d%%7Zt}X zoZf$aA7-PnAu0fRmq3&kUOqZ+y~#)S$!T|)^UF@|Y|f$UJ%hteuRB?cBmxFPLe-KW zM{2dByS|gpTw~}qy%A^oZZqDbUpr<99k;lk{CqI^Lqqej%HU*zL)Z#-@5EL~p1B|D zgSd16q%w7#7gic10=z^y(df)SkI&mWHA!T{=o=rGG@LGu6tu@2f! z9g(_{EmQpe1c)Mc-P=fwaB@d_c1Q5_E^n2GnN+FVyNt*+JX{5>X@axRPjy-lfe!l| zsNY}-BuK=uNV-iw8w0;8Uh0Z06>>=vQ?i~$KPSAewyj=dGB$WPiJ=3M&&T-K56c>e zJjvRsinoju-sl>pY4oXo$A+%^D-ow6X^k6g9OK*Sn;m2A8Dp&rhaWS9h4O63gnlru zbj_%3_Nk}T-9Q6|_>=RR@BV!1p{7#Y^Q5aj-NrDd=9R7?+Gd}6c#26*qfg-JA27t3 z^IF$1-R7Tms2)CtL}ZtX*4)qy8hkR3ca8s($Ot^tF#>nsg;4f?3ypZFxj{<1Dn9vD ztjm6YqN4ue!sq)2hEF}=$P{f0B-$O$4+NLNRda?<3;5&{8iRC*OL)spx)--w)Yqu0@4gLN#<=VXt?n@DD_d4ij zDB13He9v68J=j=(kzs5(Vtlz}+&#l==3I|3`e!KF?{$37T(sZgSbJsro(EFaQa-*q z`9FRnie;)#T5wa6+lK{u|>6MR_-96q#66b<0f{0*gwD<`?6!x*9~Gk(QxxU zOB6V+AknL+qYc5sk_AjF7?dn1mrf+Qb>Cx}vdM;o+C9Qh9>b&IHGU9KPCaB8@!(+n zdnT!uN2)zqADgggv^G*-cj=VO*JZRqQc!BFX=PkeHqU;^?^$mIc(r`#6k$%ioIb5#FH;PCWi;UUA zLj=SNazd58mv%J+a$}EP{Mw!B& zZ$4}Z##F2euW=Ml7o%B;2N;3~`2xxu>b~fIUskl$5egiSJ&;UmjN5kJWBVco$u9fX zpqMmlV1;+~vx5sM-H7Gb_&62Pl*|D*okQ+i^TmIIO{ zYFU&UJuqvp5;2WG?c9sby#srEO1G<5d{e$&*)@oWn9?2V6`O`^ymPiHE4meo5Jl5} zOkhbxtMx|sIF{1>`^fY&9AQrn7Nu-DtiL^Yb2U!E#x%eHDhpNrVDuxZTo!L^SKXrD zL6_7H0#&t*w#Bs%xvF7_QCL_{Ctekc2qmn6D`_V=1uD6)vXVCi9HP2D_WgX>i9ZzLP|pA>)E#l7xaGj+UN*M!=^_MU)Upp$D1*F!@(3S#>~~jY|%`v2Rp2?jK!&6Nfq;GMedGivbJ=8clH(5 z+iY3Kb6gL+%@*5dmEsA{IE}88jLG}9iowstw{TtUY_%2*Sgal>&#(lM@$0b97!bv2 z1nXEV77(z|w!01dmT^XK`z5YOK%*d!(5k3N_P_&VhBXRyn8fqMpsxSs?%=)J-PF6{3icy7v|rG_>~VZf5D0aZc}+XG?Jw zviq^7^NT5!ioNY%K3lk2I=Cp*AfHOM;9JQZv+{L^qe7!lt%~m|Y{cT8Rr1PMXc}gY zp0A}3eMlXGbzzlu_~cLqhP4PHs(b|1)?HeuxKOm%iO6aQ2X*~(RX{#}a@ARDgt*OD zq9e>Hkw;+0M~di)0F?nxD_{hi)jB(TYxQDQYol$i??b&PcYL8kJlTeS zdUc{Of3_>8unWxu_$v{APp}pnZ%C7gUUp?fVwTa6X4LsfbN{bf8$zU1=k!yVfLJH| z<*VcM#a(8Pjsh8~vHri&f=5ghd$-)q|0s8G7NqKIP2i_+2 z^7{2x=NI2iUY)k(An)wuW@Lls=?DNN> zncFKYITCS|{cZDqUQx9)jdDq&dIyl<@dVC}+Rd*CQGw9h@{|62N&|p3H$#K&jLfL+ z&uNsd=s7kQtXNDfPZlXlE~nSOyqZ;h?vflT1F(UFS2u6VQY)w^f$`8rUFb*4?z`vK z4rjW!XY!u2hw>P2KE9pBRyno0r6Wxie5-Pj8v?V?P_mGJza@jXZ+G~KImznh^bG7e z$||6NNbZ@;h-86SCj9rJZDkYfv@#7yQ;;DUp-Ow&P*5(WYlDeK^2BKmD__+6(Lnnp z&+HZqL>%V{&(>quO?;kbLaH&8S{f_998nppc*cS(muyT^K7xTHuno`R@P#y+RyD{9 z8xjcYoB`8+qjwXQ?#8B!nqSO9QIh+|*)6d>F`5!4MHY{4(8bP=rY27o;Hl$|jLMQQ zg%S`>JetbqfPGn5D>6}U_6pb(lnueM#`OoT6LLjk7G2TJ`cVg-D?KY}q$j~^wp`|0 ze|SSaw7j!rYAXz7ma?F--$JIe5D6AchD@dMLX}Q`?ee>=BXA{>hIrH(@J;z>r7x8m z{<_ffMcOY58Fm}_oS{ZS*+gQe3StMKzVi(@ZVpwq{Bb~YE6c(8eJ8Z3AYf^x#)u?Y znU%*u&dq|IfOGc)iq?#V)?Xz3Uk!4yWeFCq*Op-U`_nJM0brSjSildO6vqX8H1Hg+ z=X?!+u>YU~TxGV7mA46~+x~O@>dni#{paHR;`Pz~^BC7Nw*PFdw{1;8MujXYu+^+U z_1hbUppBl?Y(e$=Pi79PkEG8cRDa$*;vgB$4z1Fn6As`c$o*f1LBxgz*n%|;)8zo^gPKhBS4EPEZzSVuF~muAMQGd3Sf zRu?nuQd-LV(s{Cf zyyY~CNQ`$Pcj}6+M*{r*2|{QT~ptisf^Aeu2yYU%PqhWco?xOktENFs@K&%)$u_L zxQAYP7!KZwETspB#d7W#OGh-~_Z3Tju>s+UDNjJ!By+?~4I-i1lXH2dShU#N45Z~I zdluB6mi@7mH`|?1fXhXqXQmF(_+|f^wgNHO>qEj9kSuGW!7~9QumOGs6KQ`dTrwK! z74@8Gd{gaH7oDMaL)3~y7OYrsXUugef*;VBl@zBEqLbkxpwQrbkgbu>Ee#ug6RSC- z%E{d0yx;=BT>R%XI}JVS=I<>;L|`Z6;sBLm);wmqDKpWFJc`!jLGnVt?hgDs!Q2;& zcU5FA!u2U^s-z8OWuKwkJW(vjC7a#x^cN=iqAxqCA??IH&>YM`X| znf&(`hOnh`hxsFJ4FH4jeDE1zzt9II)WPFf*T%r zHtryw7~!jFzf&j+(k4%n;}@a@Y$AZQ(wKjRJNk*5zG>`21+ZLLz@k37zv$J`Uu3VN zzv$>M`qKSHp25!zulah7LQbQp@0sUv+RMf z#I+o!Qp_7m;)0ncAvAz;Q3=Z)guHWYX8PRtok?-J*&LybKy!Lepev|6N^p0b1i62d zEXkrZIe%>d0=@+Ukjhg%3xHYMq)UdRUW(Hj8zf7Ob`l+8;D?_Ny3&;Vyg+kppjD6a@1fR9%$q0bR|8~>Ko)b za@JF`{b?(=(Lkyp_A#8UZ&^eeOn-lmK)TynCu&?u|6*xp96DfOZK9fO$sANAiBFAf zR*P@uR~DjiY(%6|h5HC|r* zjb7}@vrh(l_sM|`H$GPH4Qg~*zUy_myUnb`2Z*A}h`iCa)&!pI&Eg(LaJ+wZFkvZwfcKDtxHtx+1Z)@i! ze&q|=?A;q3*`v*yY-RT*K49-&K=1t^@4a^L4e|`Jg?IG7%S!GwzU{!w{~b)}U*t8w z{+~q(VXcN>e|*(%|382Ix^92}fBE|5(fNJL_#*tN-nX*-vR9{Fk==;`a>; zfBDgxUB9^TWY+wm)805AA7%vKFty=8U=*djoG5{ny=lxcCJUreqdPT3JPkCQ!!zS7 zQsWm{q(&}f$ekvNMbg!_! z6joxIrjb#TNu+7-*nMpgP0b5eGzry;-Z7{TC}fCO)2U<&Cbb^2hYWg$RcacHik@sV zz3-T%OX8Jp$^87hGM~ms_ zMxoq~jvtG+8-cN$LjWDAR)c{EA%w$eBH&ag#pjVhl~>;r^O4&Rv-8QR`>*rLzg|}U z^{N>?#{gr05=no<@!mnjm?yhXs(8CrVm^8HlyaLKL@`{)D8*mxD2z;7+G;HKW&Ok} z0XS;3BA*Z%i)2Ya19?a+RuYJ{aHBlzzG-B8*WlM?3ApR^c_?D4&qK&{S+T@fC`3qS zgFz@AYn(um?~?@YI_Y5j$tn~cBs#ZB9=@)uD#PSO- zxV-V5v1orlaMhea@eq+jYis7fFH~Z+;V81&do@IxD-ttmIrUoPBtU!FirzDlJqRp* zXztU^mJ<^41<0?Nqj}&YYRanp*qz&2Z7xLO?pUQ+)rtzYP0&Z7^>_62VL62LRHwPGEt}vu&ilTjhunE znqE3XXBvT)@WgZ`un%r&Pa%rD%N8e=U-({9V->hvDq-JI}bVAlZS135m<}%$j$Z$Xy-N$c#Ln)rr0&MrSy&B-c9IfF(ZwLvP4)2~*3^;kiRo!krHY(#X=q))K0 zd9;}Un0uf$m<-XDKHETAFm?@EQb#-hdkufF|KOiC3D(~V)M@`YpS*tk@@2jL*XzmA z{_`l;bGHA~*4x%rAiO)ncIvjE%FRuSP_++ryHMrs(^-cqWAL>Rna9uC8xr~ocF zl)oCLvzrQrNSIeE7TkG=+3(?L1jw|V!WIxU69e#m{EY0O#b!Z_bjpJ^4WwT^TL^uE z+^~>K7PO@kZgjsjL6d+lqtfJt6Iy>3cMQ9nGt&(gx~Y>cJxD;KcC!$vS4;0vq}uaT z3C^TGr`kzD!w@7Z8cloYOMF$l`tkq_PD{D~WV-^IGZUI-0K?FltVv9sVugy9&-E$N zt(qjzN2o06Fdx>(Vjiy^y1?7TqG-&Z19c1rl6{c^Rw1p7&G6}+Yy=izqho*W+u>e` zC*&*fgMB4~Hr=(w263sp0GcGhx{+Z1Tk6%M-KM(*x-P-j<_Nss4!_vl3YVz~V2dv<4t&g3k(xgC^_T^^X{TEHP-sb*` znvK`(zrJ^%{&zDI&@6lxFDR}cR7W(}90j&z$I&r>txlD0^K3@5+}l744_D@beNGVv z1u*roH4=!hGY`G6YZh?t+a4?3bCh)ON zM51`e3SrMI!aTv3S~3psDtOoHJs(Rw!q28g+elDQWL<*k_v~70RB`Opl~6IOSw^aN z8|-M!gKJ$GG5!352-h?IyN{=^3!%j})3|7qzF~0@EWezKa9wW3&i!`1DBs|UL{u)B zJayl+#TrmMY%A7KtRjCSigHCp=clHw0R~UyNyKBGK`H3pTV`z6TFh37^+_2)g|#`2 z%e10(EXnL@Xc;(c(=f;MI+PcT#czuYk%k^x6D3A6V1zu_6+J*pd{kBsUAv)gd(*h_ z>ejpcheC$v;0?p-?%n*d(klhSP;Xy~5DwC!dq!0Qn$26*||4e;`&Znq5qudOTzy~Ejo z$NG$`)3(qwE>C|8!y(7z!_fL{4h=)|wmkG7kGq|X9`n{`i)b32pGBf~aDiqDd$CKn zWA>TTUK<5oU)tgLEG-y#`Peb=+Tn2Z5(wKZ8+h%>zJXV}l>@JCTZetd!{ULL*V^in zgomuU4S>RK695zvl<5ITR@SxT|h)RF$4=Z@X3?kC`J_rZlRNmAp z0sgA=qAlU3`jJ=TKYU@)IXci^(Ps`tow~=0E)K zjUvH{N1P*0`6SRUr`})56yt=eTI`31(RjN0rfKdcLs? ztGx+=CiKQ0U3!`T^M|XV@7+^!U4$Q6W0)~=NJfJdoktA6U=LTBCkl`Obf2Pi8GYp} z7_-dCJjV(Xwq}s#ptg2}VGuCJ0gI-bkNqv1lq!GqUZ@OhKl@rb(@Lw2=oltO&9$I# zwOP_UPgN!vjT`o)Kjo@}1Rf#teGreyfF+#*=OC(Kb5$51Dl@xYY*cF|j6J%W0Ggj)XZ34q;n?a|?{M2R1`@Uq=w{>9(y1UG3YKR!WVd)$ZVY5comD6n@dUkL z_e?4_mE!Zd3@TS{rFv=trx}g)nCWvddGBX`eZQ^LUK>`w%EmH#tvjv1-bF7D0ReNtj5lF% z^z_nm70pchRZgKtsPwN04DC0OO^lP>vq-a!vsnDjqllgfxg3A9Wc2e)GgUSImCeU` z-;Yhm$#}-H5z=#PyS8_dLb15P1f9Wa9n48H9xp=KBNmSBm}gouhdNR;AuI{xIt7f4 zt~!*P*9kvkXTU>e9fhaLYX~dzjKuMiWHU)Kw%p_4kL^`s2?Y&Fkr-Tjv*J7lD4o)M=MICYxFdhbB(WF3Hlr0@69K zItQ1!p5Evaopqu=gVxkkvVbdg3gtcld4t7s1{hJ;OBN!<36Q*V9s4l)E)XR`Y@U3} z&ED1Ajbze(wD?WlW4PW9<#g*=n_b*B9p05~95tP;01t=;KL^YJfQIMhba@+ivIst1X&=(|hZrUC6*^Z?~6uaXDGR@a28 z(V#BSBpkQqDAp!B6BQfgDVXpKsdk0hu-~xVrb($OVZLG6iBzkz?QExri#|ef6xR`w z1FnA~B!}(65t8Ew$#I0_*tm|692?gWlH&-;vFC9eAvuna939t}b~qj(IgXGVM@Wt% zB*$)pJVJ6DAvuna9M$VN#~|W$gyeYEkQ_%~3VR)aDUQGt&nZR{uOl$U5tyQW9f2v1 zz!Xi_5t!l#OtDi($q|^sxsJdTLqBl@rl^mO42bUY2$&`n~gU%kM|LY zSw=&eQRgQu(|q095Qu@H<6cpjkaWq+FJFC8mpR7uA*~N>m5G@Djz{2{#?fBBF_}yz zZ!Ru>;J=f}r2gNRuU@|V>ipun$*c3%7q8CWd^LgpenlpG`FhWltBlI8COdztKDaOB z8jVI@Ll_wOn>+bm)0F?hqyjc$mjydR8R_iq&q|Ac_vdq#(etmZQ5qzo7bM7KL`H%v zX~rJtdZaR%gj9wjo~VpQ(dhpC?EGv3>x+zkJ`{X-$+J~HKMO?cN{@;!)z~&gQ$Cg~ zVpK6T4#h*F<;XF%H?DsNKJc~P&w6o>7Cd4_OJkqT)!$v^bNxR@3jPPmS|-v1P9V;d z_sc0avf7YWv>HjHA#Z3^7RpQyd1=VA_qb99jUu9ho}cGQ7`4#Jsv^!CJXuPnl-5gs zwtFcH(yiXhL;v?;9)=NnpwhpK)IDg^HEedrvn>Kq*!6?G%MJV$A^CSd{R8g)!%9{@nZ2kxdH*`#)vs@ zwYtR}Gy90Jf9BQjAV_TjJ>qOBMee3df&KS;QnIn4m6&G1>V_@Z=a!}*TKY_Xi)+>U z8I#HP&gi^TsJ%;069`fX#fBK diff --git a/traefik/values.schema.json b/traefik/values.schema.json index 2dd2eba65..539f26ad6 100644 --- a/traefik/values.schema.json +++ b/traefik/values.schema.json @@ -1675,19 +1675,13 @@ "traefik-crds": { "properties": { "gateway_api": { - "type": [ - "boolean" - ] + "type": "boolean" }, "hub": { - "type": [ - "boolean" - ] + "type": "boolean" }, "traefik": { - "type": [ - "boolean" - ] + "type": "boolean" } }, "type": "object" diff --git a/traefik/values.yaml b/traefik/values.yaml index 84f35b41a..a850611d7 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -968,8 +968,8 @@ hub: traefik-crds: # -- Set all the following to false if you want to manage CRDs your-self - traefik: true # @schema type:[boolean] - hub: | # @schema type:[boolean] + traefik: true + hub: | {{ tpl "ne .Values.hub.token \"\"' . }} - gateway_api: | # @schema type:[boolean] + gateway_api: | {{ tpl "ne .Values.providers.kubernetesGateway.enabled \"\" . }} From bf37c5f2e32a47da186367f77e140f9c2a5e8583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 14 Oct 2024 14:26:06 +0200 Subject: [PATCH 03/44] fix: use Files.Glob --- traefik-crds/templates/crds.yaml | 38 ++++++-------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/traefik-crds/templates/crds.yaml b/traefik-crds/templates/crds.yaml index 84dcf5a01..a2c4de9d4 100644 --- a/traefik-crds/templates/crds.yaml +++ b/traefik-crds/templates/crds.yaml @@ -1,42 +1,18 @@ {{- if .Values.traefik -}} -{{- $files := .Files }} -{{- range tuple -"crds-files/traefik/traefik.io_ingressroutes.yaml" -"crds-files/traefik/traefik.io_ingressroutetcps.yaml" -"crds-files/traefik/traefik.io_ingressrouteudps.yaml" -"crds-files/traefik/traefik.io_middlewares.yaml" -"crds-files/traefik/traefik.io_middlewaretcps.yaml" -"crds-files/traefik/traefik.io_serverstransports.yaml" -"crds-files/traefik/traefik.io_serverstransporttcps.yaml" -"crds-files/traefik/traefik.io_tlsoptions.yaml" -"crds-files/traefik/traefik.io_tlsstores.yaml" -"crds-files/traefik/traefik.io_traefikservices.yaml" - }} -{{ $files.Get . }} +{{- range $path, $bytes := .Files.Glob "crds-files/traefik/*.yaml" }} +{{ $.Files.Get $path }} {{- end }} {{- end }} + {{- if .Values.hub -}} -{{- $files := .Files }} -{{- range tuple -"crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml" -"crds-files/hub/hub.traefik.io_apiaccesses.yaml" -"crds-files/hub/hub.traefik.io_apibundles.yaml" -"crds-files/hub/hub.traefik.io_apiplans.yaml" -"crds-files/hub/hub.traefik.io_apiportals.yaml" -"crds-files/hub/hub.traefik.io_apiratelimits.yaml" -"crds-files/hub/hub.traefik.io_apis.yaml" -"crds-files/hub/hub.traefik.io_apiversions.yaml" - }} -{{ $files.Get . }} +{{- range $path, $bytes := .Files.Glob "crds-files/hub/*.yaml" }} +{{ $.Files.Get $path }} {{- end }} {{- end }} {{- if .Values.gateway_api -}} -{{- $files := .Files }} -{{- range tuple -"crds-files/gateway/gateway-standard-install-v1.1.0.yaml" - }} -{{ $files.Get . }} +{{- range $path, $bytes := .Files.Glob "crds-files/gateway_api/*.yaml" }} +{{ $.Files.Get $path }} {{- end }} {{- end }} From 69ba344108415e2d1f0c69f0a57ea61e4089db7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 14 Oct 2024 14:57:46 +0200 Subject: [PATCH 04/44] fix: CI --- Makefile | 3 +++ hack/ct.sh | 1 + traefik-crds/values.schema.json | 8 ++++++-- traefik-crds/values.yaml | 6 +++--- traefik/charts/traefik-crds-0.0.1.tgz | Bin 126070 -> 126100 bytes traefik/values.schema.json | 4 ++-- traefik/values.yaml | 4 ++-- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index bfb25b4a3..d927b19a3 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ traefik/tests/__snapshot__: test: traefik/tests/__snapshot__ docker run ${DOCKER_ARGS} --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_HELM_UNITTEST) /charts/hack/test.sh +deps: + helm dependency update traefik + lint: docker run ${DOCKER_ARGS} --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh lint diff --git a/hack/ct.sh b/hack/ct.sh index 2a50ffc1f..06f7f69e2 100644 --- a/hack/ct.sh +++ b/hack/ct.sh @@ -3,3 +3,4 @@ git config --global --add safe.directory /charts ct $1 --config=.github/chart-testing.yaml --charts traefik/ +ct $1 --config=.github/chart-testing.yaml --charts traefik-crds/ diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index 1fe1ef7d9..cbfccd7cd 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -5,13 +5,17 @@ "description": "The Cloud Native Application Proxy", "properties": { "gateway_api": { + "default": false, "type": [ - "boolean" + "boolean", + "string" ] }, "hub": { + "default": false, "type": [ - "boolean" + "boolean", + "string" ] }, "traefik": { diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index c6ad93429..4cbd7a28f 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,3 +1,3 @@ -traefik: false # @schema type:[boolean] -gateway_api: false # @schema type:[boolean] -hub: false # @schema type:[boolean] +traefik: false # @schema type:[boolean] +gateway_api: false # @schema type:[boolean, string]; default: false +hub: false # @schema type:[boolean, string]; default: false diff --git a/traefik/charts/traefik-crds-0.0.1.tgz b/traefik/charts/traefik-crds-0.0.1.tgz index b27ef6d26118b4db53c5a9028986c769f37576b9..984a6a8b6c6c9f218bbcf8489a33d2b973ad0495 100644 GIT binary patch delta 119490 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

UuHA&zY-_> z59GJ3w+B!m&Xj+5=agH1ZAcd*O44XZ4+h`wF!@H4CB0{aCM$TC%yREBV2i0zOcrsiBeJCG zjR>-sCDmxxKxB#jo=m>3eZdYNMY(Z0aPCBk<=Rerf=m4P&<~$Z@;ABqvE~ym=HHV` zV1RBcoAZChh+Dj*W*-su&#dYm1ffkJN1QCA$jTv8p#S}z6euhoC8j!9-mnGx+%gn+ zOP?5at@>OunS4+F_t6y+p&LVl{wV+B_VT*&@1NgX|M4*=Bc(shi*=`iwI9q&w;!fI z0cJOUO%2BWqpIlr_CNZ!^L;jJ+|p$>+hRNa`~-iyS!Gssx1$%p8(t!Bc?}wlKQ6AX z@MrVa55N&;|wH!lQhxa{>On~IkZDN Vw8sx`|1SUl|NoTMWGMi&4gkuhkIn!9 delta 119353 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

Q_8{{IOv{!*fl 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 Date: Mon, 14 Oct 2024 16:09:19 +0200 Subject: [PATCH 05/44] fix: update CI --- .github/workflows/release.yml | 95 ++++++++++++++++++++++++++++++++--- .github/workflows/test.yml | 9 +++- traefik/Chart.yaml | 4 +- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71c88a367..bcd422a12 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,12 +6,14 @@ on: - master env: - tag_prefix: v + traefik_tag_prefix: traefik_v + traefik-crds_tag_prefix: traefik-crds_v jobs: test: uses: "traefik/traefik-helm-chart/.github/workflows/test.yml@master" - release: + + release-traefik: needs: test runs-on: ubuntu-latest steps: @@ -27,7 +29,7 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" git config --global --add safe.directory /charts - - name: Copy LICENSE and README.md for packaging + - name: Copy LICENSE, EXAMPLES.md and README.md for packaging run: | cp ./README.md ./traefik/README.md cp ./EXAMPLES.md ./traefik/EXAMPLES.md @@ -35,10 +37,10 @@ jobs: - name: Generate default static install run: | - kustomize build traefik/crds > traefik.yaml + kustomize build traefik-crds > traefik.yaml helm template traefik ./traefik -n traefik >> traefik.yaml - - name: Get chart verison + - name: Get chart version id: chart_version run: | echo "CHART_VERSION=$(cat traefik/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}')" >> $GITHUB_OUTPUT @@ -47,7 +49,7 @@ jobs: id: tag_exists run: | TAG_EXISTS=true - if ! [ $(git tag -l "${{ env.tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}") ]; then + if ! [ $(git tag -l "${{ env.traefik_tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}") ]; then TAG_EXISTS=false fi echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT @@ -58,7 +60,7 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} custom_tag: ${{ steps.chart_version.outputs.CHART_VERSION }} - tag_prefix: ${{ env.tag_prefix }} + tag_prefix: ${{ env.traefik_tag_prefix }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - name: Create release @@ -97,3 +99,82 @@ jobs: registry_username: traefiker registry_password: ${{ secrets.GHCR_TOKEN }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + release-traefik-crds: + needs: test + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + git config --global --add safe.directory /charts + + - name: Copy LICENSE for packaging + run: | + cp ./LICENSE ./traefik/LICENSE + + - name: Get chart version + id: chart_version + run: | + echo "CHART_VERSION=$(cat traefik-crds/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}')" >> $GITHUB_OUTPUT + + - name: Check if tag exists + id: tag_exists + run: | + TAG_EXISTS=true + if ! [ $(git tag -l "${{ env.traefik-crds_tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}") ]; then + TAG_EXISTS=false + fi + echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT + + - name: Tag release + id: tag_version + uses: mathieudutour/github-tag-action@v6.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + custom_tag: ${{ steps.chart_version.outputs.CHART_VERSION }} + tag_prefix: ${{ env.traefik-crds_tag_prefix }} + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + - name: Create release + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.tag_version.outputs.new_tag }} + name: ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} + prerelease: ${{ contains(steps.chart_version.outputs.CHART_VERSION, '-') }} + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + - name: Publish Helm chart + uses: stefanprodan/helm-gh-pages@master + with: + token: ${{ secrets.CHARTS_TOKEN }} + charts_dir: . + charts_url: https://traefik.github.io/charts + owner: traefik + repository: charts + branch: master + target_dir: traefik-crds + index_dir: . + commit_username: traefiker + commit_email: 30906710+traefiker@users.noreply.github.com + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + - name: Publish Helm chart to the ghcr.io registry + uses: appany/helm-oci-chart-releaser@v0.4.2 + with: + name: traefik-crds + repository: traefik/helm + tag: ${{ steps.chart_version.outputs.CHART_VERSION }} + path: ./traefik-crds + registry: ghcr.io + registry_username: traefiker + registry_password: ${{ secrets.GHCR_TOKEN }} + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5ed3f49b..832e2c0fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,13 +23,20 @@ jobs: git config user.name "$GITHUB_ACTOR" git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - - name: Check if values schema is up-to-date + - name: Check traefik if values schema is up-to-date uses: losisin/helm-values-schema-json-action@v1 with: input: traefik/values.yaml output: traefik/values.schema.json fail-on-diff: true + - name: Check traefik-crds if values schema is up-to-date + uses: losisin/helm-values-schema-json-action@v1 + with: + input: traefik-crds/values.yaml + output: traefik-crds/values.schema.json + fail-on-diff: true + - name: Lint run: make lint diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 91af7b126..7d4080045 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -29,5 +29,5 @@ annotations: - "chore(release): 🚀 publish v33.2.1" dependencies: - name: traefik-crds - version: "0.0.1" - repository: "file://../traefik-crds" + version: 0.0.1 + repository: https://traefik.github.io/charts From f829dd12ee8bfa1d8616c25bfe82fa44ec63b7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 14 Oct 2024 16:13:20 +0200 Subject: [PATCH 06/44] fix: add hub only when api management is enabled --- traefik/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/traefik/values.yaml b/traefik/values.yaml index 5baa12ee0..510526271 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -970,6 +970,6 @@ traefik-crds: # -- Set all the following to false if you want to manage CRDs your-self traefik: true hub: | - {{- tpl "ne .Values.hub.token \"\"' . }} + {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} gateway_api: | - {{- tpl "ne .Values.providers.kubernetesGateway.enabled \"\" . }} + {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} From c49084920fc4917614e07d2883276179b960df8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 14 Oct 2024 16:33:17 +0200 Subject: [PATCH 07/44] fix: CI --- .github/workflows/test.yml | 8 ++++++++ traefik-crds/.schema.yaml | 2 +- traefik-crds/values.schema.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 832e2c0fa..c76f9d9cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,10 @@ jobs: with: input: traefik/values.yaml output: traefik/values.schema.json + id: "https://traefik.io/traefik-helm-chart.schema.json" + title: "Traefik Proxy Helm Chart" + description: "The Cloud Native Application Proxy" + additional-properties: true fail-on-diff: true - name: Check traefik-crds if values schema is up-to-date @@ -35,6 +39,10 @@ jobs: with: input: traefik-crds/values.yaml output: traefik-crds/values.schema.json + id: "https://traefik.io/traefik-crds-helm-chart.schema.json" + title: "Traefik CRDs Helm Chart" + description: "The Cloud Native Application Proxy" + additional-properties: false fail-on-diff: true - name: Lint diff --git a/traefik-crds/.schema.yaml b/traefik-crds/.schema.yaml index c71d1b799..09783c714 100644 --- a/traefik-crds/.schema.yaml +++ b/traefik-crds/.schema.yaml @@ -10,4 +10,4 @@ schemaRoot: id: https://traefik.io/traefik-crds-helm-chart.schema.json title: Traefik CRDs Helm Chart description: The Cloud Native Application Proxy - additionalProperties: true + additionalProperties: false diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index cbfccd7cd..82c5776c2 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -1,7 +1,7 @@ { "$id": "https://traefik.io/traefik-crds-helm-chart.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": true, + "additionalProperties": false, "description": "The Cloud Native Application Proxy", "properties": { "gateway_api": { From 55ba3a8487a80caf412021fa3c291fa1c6a17ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 14 Oct 2024 16:49:23 +0200 Subject: [PATCH 08/44] fix: snapshot dir --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index d927b19a3..d0dca5f9c 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ IMAGE_HELM_UNITTEST=docker.io/helmunittest/helm-unittest:3.16.1-0.6.1 traefik/tests/__snapshot__: @mkdir traefik/tests/__snapshot__ + @mkdir traefik-crds/tests/__snapshot__ test: traefik/tests/__snapshot__ docker run ${DOCKER_ARGS} --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_HELM_UNITTEST) /charts/hack/test.sh From 77095819a73ed8518d5d4652ad8c527c5e082770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 16 Dec 2024 08:11:13 +0100 Subject: [PATCH 09/44] fix: remove dependency while not published --- traefik-crds/VALUES.md | 36 ++++++++++++++++++++++++++ traefik/Chart.lock | 6 ----- traefik/Chart.yaml | 8 +++--- traefik/charts/traefik-crds-0.0.1.tgz | Bin 126100 -> 0 bytes traefik/values.schema.json | 14 ---------- traefik/values.yaml | 14 +++++----- 6 files changed, 47 insertions(+), 31 deletions(-) create mode 100644 traefik-crds/VALUES.md delete mode 100644 traefik/Chart.lock delete mode 100644 traefik/charts/traefik-crds-0.0.1.tgz diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md new file mode 100644 index 000000000..bdeae3953 --- /dev/null +++ b/traefik-crds/VALUES.md @@ -0,0 +1,36 @@ +# traefik-crds + +![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) + +A Traefik based Kubernetes ingress controller + +**Homepage:** + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| mloiseleur | | | +| charlie-haley | | | +| darkweaver87 | | | +| jnoordsij | | | + +## Source Code + +* +* + +## Requirements + +Kubernetes: `>=1.22.0-0` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| gateway_api | bool | `false` | | +| hub | bool | `false` | | +| traefik | bool | `false` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/traefik/Chart.lock b/traefik/Chart.lock deleted file mode 100644 index 7a83ae7bb..000000000 --- a/traefik/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: traefik-crds - repository: file://../traefik-crds - version: 0.0.1 -digest: sha256:03a8641bfa1d261b699d166dea5aaa21d9e27bfc2328d157dae3809375709260 -generated: "2024-10-11T17:04:46.473483814+02:00" diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 7d4080045..17a713aac 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -27,7 +27,7 @@ annotations: artifacthub.io/changes: | - "fix(Gateway API): CRDs should only be defined once" - "chore(release): 🚀 publish v33.2.1" -dependencies: - - name: traefik-crds - version: 0.0.1 - repository: https://traefik.github.io/charts +#dependencies: +# - name: traefik-crds +# version: 0.0.1 +# repository: https://traefik.github.io/charts diff --git a/traefik/charts/traefik-crds-0.0.1.tgz b/traefik/charts/traefik-crds-0.0.1.tgz deleted file mode 100644 index 984a6a8b6c6c9f218bbcf8489a33d2b973ad0495..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126100 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 diff --git a/traefik/values.schema.json b/traefik/values.schema.json index 22878a9f5..aa76667a7 100644 --- a/traefik/values.schema.json +++ b/traefik/values.schema.json @@ -1672,20 +1672,6 @@ }, "type": "object" }, - "traefik-crds": { - "properties": { - "gateway_api": { - "type": "string" - }, - "hub": { - "type": "string" - }, - "traefik": { - "type": "boolean" - } - }, - "type": "object" - }, "updateStrategy": { "additionalProperties": false, "properties": { diff --git a/traefik/values.yaml b/traefik/values.yaml index 510526271..cc00e97da 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -966,10 +966,10 @@ hub: # Enable export of errors logs to the platform. Default: true. sendlogs: # @schema type:[boolean, null] -traefik-crds: - # -- Set all the following to false if you want to manage CRDs your-self - traefik: true - hub: | - {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} - gateway_api: | - {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} +#traefik-crds: +# # -- Set all the following to false if you want to manage CRDs your-self +# traefik: true +# hub: | +# {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} +# gateway_api: | +# {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} From fd01dc00c6c5a729026cda24d27ed201f1578923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 18 Oct 2024 08:11:57 +0200 Subject: [PATCH 10/44] fix: apply suggestions from @mloiseleur's code review Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bcd422a12..5642e73b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,14 +6,14 @@ on: - master env: - traefik_tag_prefix: traefik_v - traefik-crds_tag_prefix: traefik-crds_v + tag_prefix: v + crds_tag_prefix: crds_v jobs: test: uses: "traefik/traefik-helm-chart/.github/workflows/test.yml@master" - release-traefik: + traefik: needs: test runs-on: ubuntu-latest steps: @@ -100,7 +100,7 @@ jobs: registry_password: ${{ secrets.GHCR_TOKEN }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - release-traefik-crds: + traefik-crds: needs: test runs-on: ubuntu-latest steps: From 412fa8c885e2bca7f377fb9b913ab1fb31474f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 18 Oct 2024 09:46:05 +0200 Subject: [PATCH 11/44] fix: tag exist condition --- .github/workflows/release.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5642e73b8..f029351c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,9 +48,9 @@ jobs: - name: Check if tag exists id: tag_exists run: | - TAG_EXISTS=true - if ! [ $(git tag -l "${{ env.traefik_tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}") ]; then - TAG_EXISTS=false + TAG_EXISTS=false + if git tag -l | grep "${{ env.tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}" > /dev/null ; then + TAG_EXISTS=true fi echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT @@ -60,7 +60,7 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} custom_tag: ${{ steps.chart_version.outputs.CHART_VERSION }} - tag_prefix: ${{ env.traefik_tag_prefix }} + tag_prefix: ${{ env.tag_prefix }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - name: Create release @@ -128,9 +128,9 @@ jobs: - name: Check if tag exists id: tag_exists run: | - TAG_EXISTS=true - if ! [ $(git tag -l "${{ env.traefik-crds_tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}") ]; then - TAG_EXISTS=false + TAG_EXISTS=false + if git tag -l | grep "${{ env.crds_tag_prefix }}${{ steps.chart_version.outputs.CHART_VERSION }}" > /dev/null ; then + TAG_EXISTS=true fi echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT @@ -140,7 +140,7 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} custom_tag: ${{ steps.chart_version.outputs.CHART_VERSION }} - tag_prefix: ${{ env.traefik-crds_tag_prefix }} + tag_prefix: ${{ env.crds_tag_prefix }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - name: Create release From 31eafa9bcc662818be75ceb733b880f38f7466ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 18 Oct 2024 09:59:25 +0200 Subject: [PATCH 12/44] fix: charts_dir --- .github/workflows/release.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f029351c5..a9156fef8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,6 +73,12 @@ jobs: artifacts: "traefik.yaml" if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + # avoid helm-gh-pages to push both charts + - name: Delete traefik-crds chart + run: | + rm -rf traefik-crds + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Publish Helm chart uses: stefanprodan/helm-gh-pages@master with: @@ -152,6 +158,12 @@ jobs: prerelease: ${{ contains(steps.chart_version.outputs.CHART_VERSION, '-') }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + # avoid helm-gh-pages to push both charts + - name: Delete traefik chart + run: | + rm -rf traefik + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Publish Helm chart uses: stefanprodan/helm-gh-pages@master with: From fb5215c8b41f391c5f0997573ffcebf07d49b55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 18 Oct 2024 12:05:32 +0200 Subject: [PATCH 13/44] fix: changelog --- hack/changelog.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hack/changelog.sh b/hack/changelog.sh index a5e951a1d..5711a42d6 100755 --- a/hack/changelog.sh +++ b/hack/changelog.sh @@ -1,9 +1,9 @@ #!/bin/bash -chart="./traefik" - -version="$(awk '/^version:/ { print $2} ' ${chart}/Chart.yaml)" -changelog="$(sed -e "1,/^## ${version}/d" -e "/^###/,\$d" -e '/^$/d' -e 's/^* /- /' -e 's/^/ /' ${chart}/Changelog.md | grep '^ - ' | sed -e 's/\ *$//g' | sed 's/ - \(.*\)/ - "\1"/g')" -sed -i -e '/^ artifacthub.io\/changes: |/,$d' ${chart}/Chart.yaml -echo " artifacthub.io/changes: |" >> ${chart}/Chart.yaml -echo "${changelog}" >> ${chart}/Chart.yaml +for chart in "./traefik" "./traefik-crds"; do + version="$(awk '/^version:/ { print $2} ' ${chart}/Chart.yaml)" + changelog="$(sed -e "1,/^## ${version}/d" -e "/^###/,\$d" -e '/^$/d' -e 's/^* /- /' -e 's/^/ /' ${chart}/Changelog.md | grep '^ - ' | sed -e 's/\ *$//g' | sed 's/ - \(.*\)/ - "\1"/g')" + sed -i -e '/^ artifacthub.io\/changes: |/,$d' ${chart}/Chart.yaml + echo " artifacthub.io/changes: |" >>${chart}/Chart.yaml + echo "${changelog}" >>${chart}/Chart.yaml +done From f8dce184398923e1c664940cf3e9cc9f552db380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 21 Oct 2024 09:16:24 +0200 Subject: [PATCH 14/44] fix: get chart version --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9156fef8..bdb7f48cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,7 +43,7 @@ jobs: - name: Get chart version id: chart_version run: | - echo "CHART_VERSION=$(cat traefik/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}')" >> $GITHUB_OUTPUT + echo "CHART_VERSION=$(cat traefik/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}' | head -n 1)" >> $GITHUB_OUTPUT - name: Check if tag exists id: tag_exists @@ -129,7 +129,7 @@ jobs: - name: Get chart version id: chart_version run: | - echo "CHART_VERSION=$(cat traefik-crds/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}')" >> $GITHUB_OUTPUT + echo "CHART_VERSION=$(cat traefik-crds/Chart.yaml | awk -F"[ ',]+" '/version:/{print $2}' | head -n 1)" >> $GITHUB_OUTPUT - name: Check if tag exists id: tag_exists From 5f39c43cc9ebe01e9aa02ecfc6ce86513165b72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 21 Oct 2024 16:12:02 +0200 Subject: [PATCH 15/44] fix: reduce changelog on patches --- hack/changelog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/changelog.sh b/hack/changelog.sh index 5711a42d6..f261f73ff 100755 --- a/hack/changelog.sh +++ b/hack/changelog.sh @@ -2,7 +2,7 @@ for chart in "./traefik" "./traefik-crds"; do version="$(awk '/^version:/ { print $2} ' ${chart}/Chart.yaml)" - changelog="$(sed -e "1,/^## ${version}/d" -e "/^###/,\$d" -e '/^$/d' -e 's/^* /- /' -e 's/^/ /' ${chart}/Changelog.md | grep '^ - ' | sed -e 's/\ *$//g' | sed 's/ - \(.*\)/ - "\1"/g')" + changelog="$(sed -e "1,/^## ${version}/d" -e "/^##/,\$d" -e '/^$/d' -e 's/^* /- /' -e 's/^/ /' ${chart}/Changelog.md | grep '^ - ' | sed -e 's/\ *$//g' | sed 's/ - \(.*\)/ - "\1"/g')" sed -i -e '/^ artifacthub.io\/changes: |/,$d' ${chart}/Chart.yaml echo " artifacthub.io/changes: |" >>${chart}/Chart.yaml echo "${changelog}" >>${chart}/Chart.yaml From a5b407a56e2be6917ea7b9efcb364c7f0452a62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 21 Oct 2024 16:26:55 +0200 Subject: [PATCH 16/44] fix: ci workflow to handle two different releases --- .github/workflows/changelog.json | 53 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 56 ++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/changelog.json diff --git a/.github/workflows/changelog.json b/.github/workflows/changelog.json new file mode 100644 index 000000000..24ce6011e --- /dev/null +++ b/.github/workflows/changelog.json @@ -0,0 +1,53 @@ +{ + "template": "## [#{{TO_TAG}}](#{{RELEASE_DIFF}}) (${DATE})\n#{{CHANGELOG}}", + "categories": [ + { + "title": "## :boom: Breaking changes", + "rules": [ + { + "pattern": ".*\\((${REGEXP}).*\\)!:.*", + "on_property": "title", + "flags": "gu" + } + ] + }, + { + "title": "## :rocket: Features", + "rules": [ + { + "pattern": "feat\\((${REGEXP}).*\\):.*", + "on_property": "title", + "flags": "gu" + } + ] + }, + { + "title": "## :bug: Bug fixes", + "rules": [ + { + "pattern": "fix\\((${REGEXP}).*\\):.*", + "on_property": "title", + "flags": "gu" + } + ] + }, + { + "title": "## :package: Other", + "rules": [ + { + "pattern": "(chore|release)\\((${REGEXP}).*\\):.*", + "on_property": "title", + "flags": "gu" + } + ] + } + ], + "pr_template": "- ${{TITLE}} ##{{NUMBER}} by @#{{AUTHOR}}", + "empty_template": "- no changes", + "transformers": [ + { + "pattern": "[\\-\\*] (\\[(...|TEST|CI|SKIP)\\])( )?(.+?)\n(.+?[\\-\\*] )(.+)", + "target": "- $4\n - $6" + } + ] +} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bdb7f48cc..0e99514e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,6 +54,13 @@ jobs: fi echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT + - name: Get Previous tag + id: previous_tag + uses: "WyriHaximus/github-action-get-previous-tag@v1" + with: + prefix: v + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Tag release id: tag_version uses: mathieudutour/github-tag-action@v6.2 @@ -63,12 +70,30 @@ jobs: tag_prefix: ${{ env.tag_prefix }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Render changelog configuration + env: + REGEXP: "?!crds" + run: | + export DATE=$(date +%F); cat .github/workflows/changelog.json | envsubst > /tmp/changelog.json; cat /tmp/changelog.json + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + - name: Build Changelog + id: changelog + uses: mikepenz/release-changelog-builder-action@v5 + with: + fromTag: ${{ steps.previous_tag.outputs.tag }} + toTag: ${{ steps.tag_version.outputs.new_tag }} + configuration: "/tmp/changelog.json" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Create release uses: ncipollo/release-action@v1 with: tag: ${{ steps.tag_version.outputs.new_tag }} name: ${{ steps.tag_version.outputs.new_tag }} - body: ${{ steps.tag_version.outputs.changelog }} + body: ${{ steps.changelog.outputs.changelog }} prerelease: ${{ contains(steps.chart_version.outputs.CHART_VERSION, '-') }} artifacts: "traefik.yaml" if: steps.tag_exists.outputs.TAG_EXISTS == 'false' @@ -140,6 +165,13 @@ jobs: fi echo TAG_EXISTS=$TAG_EXISTS >> $GITHUB_OUTPUT + - name: Get Previous tag + id: previous_tag + uses: "WyriHaximus/github-action-get-previous-tag@v1" + with: + prefix: crds_v + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Tag release id: tag_version uses: mathieudutour/github-tag-action@v6.2 @@ -149,18 +181,36 @@ jobs: tag_prefix: ${{ env.crds_tag_prefix }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Render changelog configuration + env: + REGEXP: "?!crds" + run: | + export DATE=$(date +%F); cat .github/workflows/changelog.json | envsubst > /tmp/changelog.json; cat /tmp/changelog.json + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + + - name: Build Changelog + id: changelog + uses: mikepenz/release-changelog-builder-action@v5 + with: + fromTag: ${{ steps.previous_tag.outputs.tag }} + toTag: ${{ steps.tag_version.outputs.new_tag }} + configuration: "/tmp/changelog.json" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: steps.tag_exists.outputs.TAG_EXISTS == 'false' + - name: Create release uses: ncipollo/release-action@v1 with: tag: ${{ steps.tag_version.outputs.new_tag }} name: ${{ steps.tag_version.outputs.new_tag }} - body: ${{ steps.tag_version.outputs.changelog }} + body: ${{ steps.changelog.outputs.changelog }} prerelease: ${{ contains(steps.chart_version.outputs.CHART_VERSION, '-') }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' # avoid helm-gh-pages to push both charts - name: Delete traefik chart - run: | + run: | rm -rf traefik if: steps.tag_exists.outputs.TAG_EXISTS == 'false' From d0c2fc107e902d2b57f2ed3090f6de137554be7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 21 Oct 2024 16:28:24 +0200 Subject: [PATCH 17/44] fix: Chart.yaml --- traefik-crds/Chart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/traefik-crds/Chart.yaml b/traefik-crds/Chart.yaml index ac4dc30f9..1119f044d 100644 --- a/traefik-crds/Chart.yaml +++ b/traefik-crds/Chart.yaml @@ -21,3 +21,4 @@ maintainers: email: remi.buisson@traefik.io - name: jnoordsij icon: https://raw.githubusercontent.com/traefik/traefik/v2.3/docs/content/assets/img/traefik.logo.png +annotations: {} From 0ac444ecf345c02f629f7f3114e132bed76e4d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 21 Oct 2024 17:09:22 +0200 Subject: [PATCH 18/44] fix: more reliable changelog.sh --- hack/changelog.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hack/changelog.sh b/hack/changelog.sh index f261f73ff..f15d96a16 100755 --- a/hack/changelog.sh +++ b/hack/changelog.sh @@ -1,8 +1,13 @@ #!/bin/bash for chart in "./traefik" "./traefik-crds"; do - version="$(awk '/^version:/ { print $2} ' ${chart}/Chart.yaml)" + version=$(yq -r '.version' <"${chart}/Chart.yaml") changelog="$(sed -e "1,/^## ${version}/d" -e "/^##/,\$d" -e '/^$/d' -e 's/^* /- /' -e 's/^/ /' ${chart}/Changelog.md | grep '^ - ' | sed -e 's/\ *$//g' | sed 's/ - \(.*\)/ - "\1"/g')" + + echo "${version}" + echo "${changelog}" + + sed -i -r 's/^annotations: \{\}/annotations:/g' ${chart}/Chart.yaml sed -i -e '/^ artifacthub.io\/changes: |/,$d' ${chart}/Chart.yaml echo " artifacthub.io/changes: |" >>${chart}/Chart.yaml echo "${changelog}" >>${chart}/Chart.yaml From 4a36ec0e3cc2919afa4fa4c514359a4f2dd40122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 23 Oct 2024 07:45:20 +0200 Subject: [PATCH 19/44] fix: apply suggestions from @mloiseleur's code review Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- .github/workflows/changelog.json | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/changelog.json b/.github/workflows/changelog.json index 24ce6011e..adf70f36f 100644 --- a/.github/workflows/changelog.json +++ b/.github/workflows/changelog.json @@ -2,7 +2,7 @@ "template": "## [#{{TO_TAG}}](#{{RELEASE_DIFF}}) (${DATE})\n#{{CHANGELOG}}", "categories": [ { - "title": "## :boom: Breaking changes", + "title": "## :boom: BREAKING CHANGES", "rules": [ { "pattern": ".*\\((${REGEXP}).*\\)!:.*", @@ -32,7 +32,7 @@ ] }, { - "title": "## :package: Other", + "title": "## :package: Others", "rules": [ { "pattern": "(chore|release)\\((${REGEXP}).*\\):.*", diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e99514e6..296208e2f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -98,7 +98,7 @@ jobs: artifacts: "traefik.yaml" if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - # avoid helm-gh-pages to push both charts + # avoid to push both charts - name: Delete traefik-crds chart run: | rm -rf traefik-crds @@ -208,7 +208,7 @@ jobs: prerelease: ${{ contains(steps.chart_version.outputs.CHART_VERSION, '-') }} if: steps.tag_exists.outputs.TAG_EXISTS == 'false' - # avoid helm-gh-pages to push both charts + # avoid to push both charts - name: Delete traefik chart run: | rm -rf traefik From 958b1e32af2f88d31e4df153197ddb73ba145ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Tue, 29 Oct 2024 14:41:51 +0100 Subject: [PATCH 20/44] fix: preserve CRDs by default --- traefik-crds/VALUES.md | 1 + traefik-crds/templates/_helpers.tpl | 20 ++++++++++++++++++++ traefik-crds/templates/crds.yaml | 13 +++---------- traefik-crds/tests/crds_test.yaml | 27 +++++++++++++++++++++++++++ traefik-crds/values.schema.json | 5 +++++ traefik-crds/values.yaml | 1 + 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 traefik-crds/templates/_helpers.tpl diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index bdeae3953..a736566bc 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -28,6 +28,7 @@ Kubernetes: `>=1.22.0-0` | Key | Type | Default | Description | |-----|------|---------|-------------| +| deleteOnUninstall | bool | `false` | | | gateway_api | bool | `false` | | | hub | bool | `false` | | | traefik | bool | `false` | | diff --git a/traefik-crds/templates/_helpers.tpl b/traefik-crds/templates/_helpers.tpl new file mode 100644 index 000000000..b1da60202 --- /dev/null +++ b/traefik-crds/templates/_helpers.tpl @@ -0,0 +1,20 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Render CRDs file. +*/}} +{{- define "traefik-crds.render-crds" -}} + {{- $scope := .scope -}} + {{- range $path, $bytes := $scope.Files.Glob .path }} + {{- range $doc := regexSplit "\n---\n" ($scope.Files.Get $path) -1 }} + {{- $crd := $doc | fromYaml -}} + {{ with $crd }} + {{- if not $scope.Values.deleteOnUninstall -}} + {{- $_ := set $crd.metadata.annotations "helm.sh/resource-policy" "keep" -}} + {{- end }} +--- +{{ $crd | toYaml }} + {{- end }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/traefik-crds/templates/crds.yaml b/traefik-crds/templates/crds.yaml index a2c4de9d4..b7c283a19 100644 --- a/traefik-crds/templates/crds.yaml +++ b/traefik-crds/templates/crds.yaml @@ -1,18 +1,11 @@ {{- if .Values.traefik -}} -{{- range $path, $bytes := .Files.Glob "crds-files/traefik/*.yaml" }} -{{ $.Files.Get $path }} +{{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/traefik/*.yaml") }} {{- end }} -{{- end }} - {{- if .Values.hub -}} -{{- range $path, $bytes := .Files.Glob "crds-files/hub/*.yaml" }} -{{ $.Files.Get $path }} -{{- end }} +{{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/hub/*.yaml") }} {{- end }} {{- if .Values.gateway_api -}} -{{- range $path, $bytes := .Files.Glob "crds-files/gateway_api/*.yaml" }} -{{ $.Files.Get $path }} -{{- end }} +{{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/gateway_api/*.yaml") }} {{- end }} diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml index deeef0b22..8e6d12ddf 100644 --- a/traefik-crds/tests/crds_test.yaml +++ b/traefik-crds/tests/crds_test.yaml @@ -21,6 +21,9 @@ tests: - matchRegex: path: spec.names.kind pattern: ^(IngressRoute|IngressRouteTCP|IngressRouteUDP|Middleware|MiddlewareTCP|ServersTransport|ServersTransportTCP|TLSOption|TLSStore|TraefikService)$ + - equal: + path: metadata.annotations["helm.sh/resource-policy"] + value: keep - it: should have all Traefik Hub crds set: @@ -36,6 +39,9 @@ tests: - matchRegex: path: spec.names.kind pattern: ^(AccessControlPolicy|APIAccess|APIBundle|APIPlan|APIPortal|APIRateLimit|API|APIVersion)$ + - equal: + path: metadata.annotations["helm.sh/resource-policy"] + value: keep - it: should have all Gateway API crds set: @@ -51,3 +57,24 @@ tests: - matchRegex: path: spec.names.kind pattern: ^(GatewayClass|Gateway|GRPCRoute|HTTPRoute|ReferenceGrant)$ + - equal: + path: metadata.annotations["helm.sh/resource-policy"] + value: keep + + - it: should have all Gateway API crds without helm keep resource policy + set: + gateway_api: true + deleteOnUninstall: true + asserts: + - hasDocuments: + count: 5 + - isKind: + of: CustomResourceDefinition + - equal: + path: spec.group + value: gateway.networking.k8s.io + - matchRegex: + path: spec.names.kind + pattern: ^(GatewayClass|Gateway|GRPCRoute|HTTPRoute|ReferenceGrant)$ + - notExists: + path: metadata.annotations["helm.sh/resource-policy"] diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index 82c5776c2..fbc7b04ac 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -4,6 +4,11 @@ "additionalProperties": false, "description": "The Cloud Native Application Proxy", "properties": { + "deleteOnUninstall": { + "type": [ + "boolean" + ] + }, "gateway_api": { "default": false, "type": [ diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index 4cbd7a28f..7e62df857 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,3 +1,4 @@ traefik: false # @schema type:[boolean] gateway_api: false # @schema type:[boolean, string]; default: false hub: false # @schema type:[boolean, string]; default: false +deleteOnUninstall: false # @schema type:[boolean] From 09c242089ac54e747751caef68212a230f7e1330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 30 Oct 2024 07:55:10 +0100 Subject: [PATCH 21/44] fix: add some annotations on CRDs --- traefik-crds/templates/_helpers.tpl | 2 ++ traefik-crds/values.schema.json | 14 ++++++++++---- traefik-crds/values.yaml | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/traefik-crds/templates/_helpers.tpl b/traefik-crds/templates/_helpers.tpl index b1da60202..e43c7aa39 100644 --- a/traefik-crds/templates/_helpers.tpl +++ b/traefik-crds/templates/_helpers.tpl @@ -9,6 +9,8 @@ Render CRDs file. {{- range $doc := regexSplit "\n---\n" ($scope.Files.Get $path) -1 }} {{- $crd := $doc | fromYaml -}} {{ with $crd }} + {{- set $crd.metadata.annotations "app.kubernetes.io/managed-by" "Helm" -}} + {{- set $crd.metadata.annotations "meta.helm.sh/release-name" .Release.Name -}} {{- if not $scope.Values.deleteOnUninstall -}} {{- $_ := set $crd.metadata.annotations "helm.sh/resource-policy" "keep" -}} {{- end }} diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index fbc7b04ac..79a08cfe7 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -12,15 +12,21 @@ "gateway_api": { "default": false, "type": [ - "boolean", - "string" + "string", + "boolean" + ] + }, + "global": { + "additionalProperties": true, + "type": [ + "object" ] }, "hub": { "default": false, "type": [ - "boolean", - "string" + "string", + "boolean" ] }, "traefik": { diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index 7e62df857..a31b3f309 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,4 +1,5 @@ +global: # @schema type:[object]; additionalProperties: true traefik: false # @schema type:[boolean] -gateway_api: false # @schema type:[boolean, string]; default: false -hub: false # @schema type:[boolean, string]; default: false +gateway_api: false # @schema type:[string, boolean]; default: false +hub: false # @schema type:[string, boolean]; default: false deleteOnUninstall: false # @schema type:[boolean] From dc9036416cd644df6c2c0d7c0ceb61fe5e539c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 30 Oct 2024 10:45:08 +0100 Subject: [PATCH 22/44] fix: schemas and helper --- traefik-crds/templates/_helpers.tpl | 20 ++++++++++++++++---- traefik-crds/templates/crds.yaml | 4 ++-- traefik-crds/values.schema.json | 3 ++- traefik-crds/values.yaml | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/traefik-crds/templates/_helpers.tpl b/traefik-crds/templates/_helpers.tpl index e43c7aa39..6342768ef 100644 --- a/traefik-crds/templates/_helpers.tpl +++ b/traefik-crds/templates/_helpers.tpl @@ -9,13 +9,25 @@ Render CRDs file. {{- range $doc := regexSplit "\n---\n" ($scope.Files.Get $path) -1 }} {{- $crd := $doc | fromYaml -}} {{ with $crd }} - {{- set $crd.metadata.annotations "app.kubernetes.io/managed-by" "Helm" -}} - {{- set $crd.metadata.annotations "meta.helm.sh/release-name" .Release.Name -}} + {{- $labelsAndAnnotations := + (dict "metadata" (dict + "annotations" (dict + "app.kubernetes.io/managed-by" "Helm" + "meta.helm.sh/release-name" $scope.Release.Name + "meta.helm.sh/release-namespace" $scope.Release.Namespace + ) + "labels" (dict + "app.kubernetes.io/managed-by" "Helm" + ) + )) + -}} {{- if not $scope.Values.deleteOnUninstall -}} - {{- $_ := set $crd.metadata.annotations "helm.sh/resource-policy" "keep" -}} + {{- $_ := set $labelsAndAnnotations.metadata.annotations "helm.sh/resource-policy" "keep" -}} {{- end }} + {{- $newCrd := merge $crd $labelsAndAnnotations }} --- -{{ $crd | toYaml }} +# source: {{ $path }} +{{ $newCrd | toYaml }} {{- end }} {{- end }} {{- end }} diff --git a/traefik-crds/templates/crds.yaml b/traefik-crds/templates/crds.yaml index b7c283a19..9440dd591 100644 --- a/traefik-crds/templates/crds.yaml +++ b/traefik-crds/templates/crds.yaml @@ -2,10 +2,10 @@ {{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/traefik/*.yaml") }} {{- end }} -{{- if .Values.hub -}} +{{- if eq (.Values.hub | toString) "true" -}} {{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/hub/*.yaml") }} {{- end }} -{{- if .Values.gateway_api -}} +{{- if eq (.Values.gateway_api | toString) "true" -}} {{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/gateway_api/*.yaml") }} {{- end }} diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index 79a08cfe7..7189c84bb 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -19,7 +19,8 @@ "global": { "additionalProperties": true, "type": [ - "object" + "object", + "null" ] }, "hub": { diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index a31b3f309..bd3a42a72 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,4 +1,4 @@ -global: # @schema type:[object]; additionalProperties: true +global: # @schema type:[object, null]; additionalProperties: true traefik: false # @schema type:[boolean] gateway_api: false # @schema type:[string, boolean]; default: false hub: false # @schema type:[string, boolean]; default: false From ff1c67657c31ce5c073065293af9a12bda058574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 4 Nov 2024 08:18:12 +0100 Subject: [PATCH 23/44] fix: doc --- README.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 34c898ef5..686e50bbf 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,6 @@ helm install -f myvalues.yaml traefik traefik/traefik One can check what has changed in the [Changelog](./traefik/Changelog.md). -:information_source: With Helm v3, CRDs created by this chart can not be updated, cf. the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions). - :warning: Please read carefully release notes of this chart before upgrading CRDs. ```bash @@ -90,13 +88,42 @@ One can check what has changed in the [Changelog](./traefik/Changelog.md). helm repo update # See current Chart & Traefik version helm search repo traefik/traefik +# Upgrade Traefik +helm upgrade traefik traefik/traefik +``` + +If you opt-out CRDs management system, you can still apply it manually: + +```bash # Update CRDs (Traefik Proxy v3 CRDs) kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik-crds/ +``` + +New major version indicates that there is an incompatible breaking change. + +### Upgrade to 34.X + +Starting from this release, the new traefik helm CRD management which works around [Helm caveats](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations) system is enabled by default: + +```bash +# Update repository +helm repo update +# See current Chart & Traefik version +helm search repo traefik/traefik +# Change CRDs ownership +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' +# If you use gateway API, you might also want to change Gateway API ownership + kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' # Upgrade Traefik helm upgrade traefik traefik/traefik ``` -New major version indicates that there is an incompatible breaking change. +If you still want to manage CRDs your self, it can be opt-out: + +```bash +# Upgrade Traefik and skip all CRDs installation +helm upgrade traefik traefik/traefik --set traefik-crds.traefik=false --set traefik-crds.hub=false --set traefik-crds.gateway_api=false +``` ### Upgrade up to 27.X From 39fc5a37ec7d7661f80da65923d07378ae55f6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Thu, 31 Oct 2024 09:38:37 +0100 Subject: [PATCH 24/44] fix: CI --- traefik-crds/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index bd3a42a72..e68d5f04d 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,4 +1,4 @@ -global: # @schema type:[object, null]; additionalProperties: true +global: # @schema type:[object, null]; additionalProperties: true traefik: false # @schema type:[boolean] gateway_api: false # @schema type:[string, boolean]; default: false hub: false # @schema type:[string, boolean]; default: false From 2af71bcdd2788f7a2f964ca464a8cf7b31de34c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 4 Nov 2024 08:25:40 +0100 Subject: [PATCH 25/44] fix: CI --- traefik-crds/VALUES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index a736566bc..68d56e701 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -30,6 +30,7 @@ Kubernetes: `>=1.22.0-0` |-----|------|---------|-------------| | deleteOnUninstall | bool | `false` | | | gateway_api | bool | `false` | | +| global | string | `nil` | | | hub | bool | `false` | | | traefik | bool | `false` | | From 34e03a94987414c717f27db289861c052f16e034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 8 Nov 2024 09:02:10 +0100 Subject: [PATCH 26/44] fix: review --- traefik-crds/values.schema.json | 8 ++------ traefik-crds/values.yaml | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index 7189c84bb..99668a020 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -5,9 +5,7 @@ "description": "The Cloud Native Application Proxy", "properties": { "deleteOnUninstall": { - "type": [ - "boolean" - ] + "type": "boolean" }, "gateway_api": { "default": false, @@ -31,9 +29,7 @@ ] }, "traefik": { - "type": [ - "boolean" - ] + "type": "boolean" } }, "title": "Traefik CRDs Helm Chart", diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index e68d5f04d..bc5f1b94f 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,5 +1,5 @@ global: # @schema type:[object, null]; additionalProperties: true -traefik: false # @schema type:[boolean] +traefik: false gateway_api: false # @schema type:[string, boolean]; default: false hub: false # @schema type:[string, boolean]; default: false -deleteOnUninstall: false # @schema type:[boolean] +deleteOnUninstall: false From ac7881b0d2ceea1348103417003d0082b652041f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 8 Nov 2024 09:04:50 +0100 Subject: [PATCH 27/44] fix: doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 686e50bbf..69b738df7 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ helm search repo traefik/traefik # Change CRDs ownership kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' # If you use gateway API, you might also want to change Gateway API ownership - kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' # Upgrade Traefik helm upgrade traefik traefik/traefik ``` From 8d8137838003dcc830a2f286729113afc8e733c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 16 Dec 2024 08:11:37 +0100 Subject: [PATCH 28/44] fix: tests + add condition --- traefik-crds/tests/crds_test.yaml | 4 ++-- traefik/Chart.yaml | 9 +++++---- traefik/values.schema.json | 14 ++++++++++++++ traefik/values.yaml | 14 +++++++------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml index 8e6d12ddf..ce1ce07c1 100644 --- a/traefik-crds/tests/crds_test.yaml +++ b/traefik-crds/tests/crds_test.yaml @@ -30,7 +30,7 @@ tests: hub: true asserts: - hasDocuments: - count: 8 + count: 11 - isKind: of: CustomResourceDefinition - equal: @@ -38,7 +38,7 @@ tests: value: hub.traefik.io - matchRegex: path: spec.names.kind - pattern: ^(AccessControlPolicy|APIAccess|APIBundle|APIPlan|APIPortal|APIRateLimit|API|APIVersion)$ + pattern: ^(AccessControlPolicy|AIService|APIAccess|APIBundle|APICatalogItem|APIPlan|APIPortal|APIRateLimit|API|APIVersion|ManagedSubscription)$ - equal: path: metadata.annotations["helm.sh/resource-policy"] value: keep diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 17a713aac..827dcd369 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -27,7 +27,8 @@ annotations: artifacthub.io/changes: | - "fix(Gateway API): CRDs should only be defined once" - "chore(release): 🚀 publish v33.2.1" -#dependencies: -# - name: traefik-crds -# version: 0.0.1 -# repository: https://traefik.github.io/charts +dependencies: + - name: traefik-crds + version: 0.0.1 + repository: https://traefik.github.io/charts + condition: or traefik-crds.traefik traefik-crds.hub traefik-crds.gateway_api diff --git a/traefik/values.schema.json b/traefik/values.schema.json index aa76667a7..22878a9f5 100644 --- a/traefik/values.schema.json +++ b/traefik/values.schema.json @@ -1672,6 +1672,20 @@ }, "type": "object" }, + "traefik-crds": { + "properties": { + "gateway_api": { + "type": "string" + }, + "hub": { + "type": "string" + }, + "traefik": { + "type": "boolean" + } + }, + "type": "object" + }, "updateStrategy": { "additionalProperties": false, "properties": { diff --git a/traefik/values.yaml b/traefik/values.yaml index cc00e97da..510526271 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -966,10 +966,10 @@ hub: # Enable export of errors logs to the platform. Default: true. sendlogs: # @schema type:[boolean, null] -#traefik-crds: -# # -- Set all the following to false if you want to manage CRDs your-self -# traefik: true -# hub: | -# {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} -# gateway_api: | -# {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} +traefik-crds: + # -- Set all the following to false if you want to manage CRDs your-self + traefik: true + hub: | + {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} + gateway_api: | + {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} From 605bf170bd9d7851d0b12aaaed027b0dae65b9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 6 Dec 2024 14:57:51 +0100 Subject: [PATCH 29/44] fix --- traefik/crds/traefik.io_ingressroutes.yaml | 366 ++++++ traefik/crds/traefik.io_ingressroutetcps.yaml | 247 ++++ traefik/crds/traefik.io_ingressrouteudps.yaml | 111 ++ traefik/crds/traefik.io_middlewares.yaml | 1126 +++++++++++++++++ traefik/crds/traefik.io_middlewaretcps.yaml | 87 ++ .../crds/traefik.io_serverstransports.yaml | 139 ++ .../crds/traefik.io_serverstransporttcps.yaml | 120 ++ traefik/crds/traefik.io_tlsoptions.yaml | 114 ++ traefik/crds/traefik.io_tlsstores.yaml | 97 ++ traefik/crds/traefik.io_traefikservices.yaml | 644 ++++++++++ 10 files changed, 3051 insertions(+) create mode 100644 traefik/crds/traefik.io_ingressroutes.yaml create mode 100644 traefik/crds/traefik.io_ingressroutetcps.yaml create mode 100644 traefik/crds/traefik.io_ingressrouteudps.yaml create mode 100644 traefik/crds/traefik.io_middlewares.yaml create mode 100644 traefik/crds/traefik.io_middlewaretcps.yaml create mode 100644 traefik/crds/traefik.io_serverstransports.yaml create mode 100644 traefik/crds/traefik.io_serverstransporttcps.yaml create mode 100644 traefik/crds/traefik.io_tlsoptions.yaml create mode 100644 traefik/crds/traefik.io_tlsstores.yaml create mode 100644 traefik/crds/traefik.io_traefikservices.yaml diff --git a/traefik/crds/traefik.io_ingressroutes.yaml b/traefik/crds/traefik.io_ingressroutes.yaml new file mode 100644 index 000000000..ccb374a94 --- /dev/null +++ b/traefik/crds/traefik.io_ingressroutes.yaml @@ -0,0 +1,366 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: ingressroutes.traefik.io +spec: + group: traefik.io + names: + kind: IngressRoute + listKind: IngressRouteList + plural: ingressroutes + singular: ingressroute + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IngressRoute is the CRD implementation of a Traefik HTTP Router. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IngressRouteSpec defines the desired state of IngressRoute. + properties: + entryPoints: + description: |- + EntryPoints defines the list of entry point names to bind to. + Entry points have to be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/entrypoints/ + Default: all. + items: + type: string + type: array + routes: + description: Routes defines the list of routes. + items: + description: Route holds the HTTP route configuration. + properties: + kind: + description: |- + Kind defines the kind of the route. + Rule is the only supported kind. + enum: + - Rule + type: string + match: + description: |- + Match defines the router's rule. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rule + type: string + middlewares: + description: |- + Middlewares defines the list of references to Middleware resources. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-middleware + items: + description: MiddlewareRef is a reference to a Middleware + resource. + properties: + name: + description: Name defines the name of the referenced Middleware + resource. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Middleware resource. + type: string + required: + - name + type: object + type: array + priority: + description: |- + Priority defines the router's priority. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#priority + type: integer + services: + description: |- + Services defines the list of Service. + It can contain any combination of TraefikService and/or reference to a Kubernetes Service. + items: + description: Service defines an upstream HTTP service to proxy + traffic to. + properties: + healthCheck: + description: Healthcheck defines health checks for ExternalName + services. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be + sent to the health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname + in the Host header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for + the health check endpoint. + type: string + port: + description: Port defines the server URL port for + the health check endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme + for the health check endpoint. + type: string + status: + description: Status defines the expected HTTP status + code of the response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + type: object + kind: + description: Kind defines the kind of the Service. + enum: + - Service + - TraefikService + type: string + name: + description: |- + Name defines the name of the referenced Kubernetes Service or TraefikService. + The differentiation between the two is specified in the Kind field. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service or TraefikService. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + passHostHeader: + description: |- + PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service. + By default, passHostHeader is true. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + responseForwarding: + description: ResponseForwarding defines how Traefik forwards + the response from the upstream Kubernetes Service to + the client. + properties: + flushInterval: + description: |- + FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body. + A negative value means to flush immediately after each write to the client. + This configuration is ignored when ReverseProxy recognizes a response as a streaming response; + for such responses, writes are flushed to the client immediately. + Default: 100ms + type: string + type: object + scheme: + description: |- + Scheme defines the scheme to use for the request to the upstream Kubernetes Service. + It defaults to https when Kubernetes Service port is 443, http otherwise. + type: string + serversTransport: + description: |- + ServersTransport defines the name of ServersTransport resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + sticky: + description: |- + Sticky defines the sticky sessions configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#sticky-sessions + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie + can be accessed by client-side APIs, such as + JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie + can only be transmitted over an encrypted connection + (i.e. HTTPS). + type: boolean + type: object + type: object + strategy: + description: |- + Strategy defines the load balancing strategy between the servers. + RoundRobin is the only supported value at the moment. + type: string + weight: + description: |- + Weight defines the weight and should only be specified when Name references a TraefikService object + (and to be precise, one that embeds a Weighted Round Robin). + type: integer + required: + - name + type: object + type: array + syntax: + description: |- + Syntax defines the router's rule syntax. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax + type: string + required: + - kind + - match + type: object + type: array + tls: + description: |- + TLS defines the TLS configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#tls + properties: + certResolver: + description: |- + CertResolver defines the name of the certificate resolver to use. + Cert resolvers have to be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/https/acme/#certificate-resolvers + type: string + domains: + description: |- + Domains defines the list of domains that will be used to issue certificates. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#domains + items: + description: Domain holds a domain name with SANs. + properties: + main: + description: Main defines the main domain name. + type: string + sans: + description: SANs defines the subject alternative domain + names. + items: + type: string + type: array + type: object + type: array + options: + description: |- + Options defines the reference to a TLSOption, that specifies the parameters of the TLS connection. + If not defined, the `default` TLSOption is used. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#tls-options + properties: + name: + description: |- + Name defines the name of the referenced TLSOption. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-tlsoption + type: string + namespace: + description: |- + Namespace defines the namespace of the referenced TLSOption. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-tlsoption + type: string + required: + - name + type: object + secretName: + description: SecretName is the name of the referenced Kubernetes + Secret to specify the certificate details. + type: string + store: + description: |- + Store defines the reference to the TLSStore, that will be used to store certificates. + Please note that only `default` TLSStore can be used. + properties: + name: + description: |- + Name defines the name of the referenced TLSStore. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-tlsstore + type: string + namespace: + description: |- + Namespace defines the namespace of the referenced TLSStore. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-tlsstore + type: string + required: + - name + type: object + type: object + required: + - routes + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_ingressroutetcps.yaml b/traefik/crds/traefik.io_ingressroutetcps.yaml new file mode 100644 index 000000000..ae675f6a6 --- /dev/null +++ b/traefik/crds/traefik.io_ingressroutetcps.yaml @@ -0,0 +1,247 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: ingressroutetcps.traefik.io +spec: + group: traefik.io + names: + kind: IngressRouteTCP + listKind: IngressRouteTCPList + plural: ingressroutetcps + singular: ingressroutetcp + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IngressRouteTCP is the CRD implementation of a Traefik TCP Router. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IngressRouteTCPSpec defines the desired state of IngressRouteTCP. + properties: + entryPoints: + description: |- + EntryPoints defines the list of entry point names to bind to. + Entry points have to be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/entrypoints/ + Default: all. + items: + type: string + type: array + routes: + description: Routes defines the list of routes. + items: + description: RouteTCP holds the TCP route configuration. + properties: + match: + description: |- + Match defines the router's rule. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rule_1 + type: string + middlewares: + description: Middlewares defines the list of references to MiddlewareTCP + resources. + items: + description: ObjectReference is a generic reference to a Traefik + resource. + properties: + name: + description: Name defines the name of the referenced Traefik + resource. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Traefik resource. + type: string + required: + - name + type: object + type: array + priority: + description: |- + Priority defines the router's priority. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#priority_1 + type: integer + services: + description: Services defines the list of TCP services. + items: + description: ServiceTCP defines an upstream TCP service to + proxy traffic to. + properties: + name: + description: Name defines the name of the referenced Kubernetes + Service. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + proxyProtocol: + description: |- + ProxyProtocol defines the PROXY protocol configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#proxy-protocol + properties: + version: + description: Version defines the PROXY Protocol version + to use. + type: integer + type: object + serversTransport: + description: |- + ServersTransport defines the name of ServersTransportTCP resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + terminationDelay: + description: |- + TerminationDelay defines the deadline that the proxy sets, after one of its connected peers indicates + it has closed the writing capability of its connection, to close the reading capability as well, + hence fully terminating the connection. + It is a duration in milliseconds, defaulting to 100. + A negative value means an infinite deadline (i.e. the reading capability is never closed). + Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead. + type: integer + tls: + description: TLS determines whether to use TLS when dialing + with the backend. + type: boolean + weight: + description: Weight defines the weight used when balancing + requests between multiple Kubernetes Service. + type: integer + required: + - name + - port + type: object + type: array + syntax: + description: |- + Syntax defines the router's rule syntax. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax_1 + type: string + required: + - match + type: object + type: array + tls: + description: |- + TLS defines the TLS configuration on a layer 4 / TCP Route. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#tls_1 + properties: + certResolver: + description: |- + CertResolver defines the name of the certificate resolver to use. + Cert resolvers have to be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/https/acme/#certificate-resolvers + type: string + domains: + description: |- + Domains defines the list of domains that will be used to issue certificates. + More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#domains + items: + description: Domain holds a domain name with SANs. + properties: + main: + description: Main defines the main domain name. + type: string + sans: + description: SANs defines the subject alternative domain + names. + items: + type: string + type: array + type: object + type: array + options: + description: |- + Options defines the reference to a TLSOption, that specifies the parameters of the TLS connection. + If not defined, the `default` TLSOption is used. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#tls-options + properties: + name: + description: Name defines the name of the referenced Traefik + resource. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Traefik resource. + type: string + required: + - name + type: object + passthrough: + description: Passthrough defines whether a TLS router will terminate + the TLS connection. + type: boolean + secretName: + description: SecretName is the name of the referenced Kubernetes + Secret to specify the certificate details. + type: string + store: + description: |- + Store defines the reference to the TLSStore, that will be used to store certificates. + Please note that only `default` TLSStore can be used. + properties: + name: + description: Name defines the name of the referenced Traefik + resource. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Traefik resource. + type: string + required: + - name + type: object + type: object + required: + - routes + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_ingressrouteudps.yaml b/traefik/crds/traefik.io_ingressrouteudps.yaml new file mode 100644 index 000000000..a815d8683 --- /dev/null +++ b/traefik/crds/traefik.io_ingressrouteudps.yaml @@ -0,0 +1,111 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: ingressrouteudps.traefik.io +spec: + group: traefik.io + names: + kind: IngressRouteUDP + listKind: IngressRouteUDPList + plural: ingressrouteudps + singular: ingressrouteudp + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IngressRouteUDP is a CRD implementation of a Traefik UDP Router. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IngressRouteUDPSpec defines the desired state of a IngressRouteUDP. + properties: + entryPoints: + description: |- + EntryPoints defines the list of entry point names to bind to. + Entry points have to be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/entrypoints/ + Default: all. + items: + type: string + type: array + routes: + description: Routes defines the list of routes. + items: + description: RouteUDP holds the UDP route configuration. + properties: + services: + description: Services defines the list of UDP services. + items: + description: ServiceUDP defines an upstream UDP service to + proxy traffic to. + properties: + name: + description: Name defines the name of the referenced Kubernetes + Service. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + weight: + description: Weight defines the weight used when balancing + requests between multiple Kubernetes Service. + type: integer + required: + - name + - port + type: object + type: array + type: object + type: array + required: + - routes + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_middlewares.yaml b/traefik/crds/traefik.io_middlewares.yaml new file mode 100644 index 000000000..f3ea9fc58 --- /dev/null +++ b/traefik/crds/traefik.io_middlewares.yaml @@ -0,0 +1,1126 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: middlewares.traefik.io +spec: + group: traefik.io + names: + kind: Middleware + listKind: MiddlewareList + plural: middlewares + singular: middleware + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Middleware is the CRD implementation of a Traefik Middleware. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/overview/ + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MiddlewareSpec defines the desired state of a Middleware. + properties: + addPrefix: + description: |- + AddPrefix holds the add prefix middleware configuration. + This middleware updates the path of a request before forwarding it. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/addprefix/ + properties: + prefix: + description: |- + Prefix is the string to add before the current path in the requested URL. + It should include a leading slash (/). + type: string + type: object + basicAuth: + description: |- + BasicAuth holds the basic auth middleware configuration. + This middleware restricts access to your services to known users. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/basicauth/ + properties: + headerField: + description: |- + HeaderField defines a header field to store the authenticated user. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/basicauth/#headerfield + type: string + realm: + description: |- + Realm allows the protected resources on a server to be partitioned into a set of protection spaces, each with its own authentication scheme. + Default: traefik. + type: string + removeHeader: + description: |- + RemoveHeader sets the removeHeader option to true to remove the authorization header before forwarding the request to your service. + Default: false. + type: boolean + secret: + description: Secret is the name of the referenced Kubernetes Secret + containing user credentials. + type: string + type: object + buffering: + description: |- + Buffering holds the buffering middleware configuration. + This middleware retries or limits the size of requests that can be forwarded to backends. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/buffering/#maxrequestbodybytes + properties: + maxRequestBodyBytes: + description: |- + MaxRequestBodyBytes defines the maximum allowed body size for the request (in bytes). + If the request exceeds the allowed size, it is not forwarded to the service, and the client gets a 413 (Request Entity Too Large) response. + Default: 0 (no maximum). + format: int64 + type: integer + maxResponseBodyBytes: + description: |- + MaxResponseBodyBytes defines the maximum allowed response size from the service (in bytes). + If the response exceeds the allowed size, it is not forwarded to the client. The client gets a 500 (Internal Server Error) response instead. + Default: 0 (no maximum). + format: int64 + type: integer + memRequestBodyBytes: + description: |- + MemRequestBodyBytes defines the threshold (in bytes) from which the request will be buffered on disk instead of in memory. + Default: 1048576 (1Mi). + format: int64 + type: integer + memResponseBodyBytes: + description: |- + MemResponseBodyBytes defines the threshold (in bytes) from which the response will be buffered on disk instead of in memory. + Default: 1048576 (1Mi). + format: int64 + type: integer + retryExpression: + description: |- + RetryExpression defines the retry conditions. + It is a logical combination of functions with operators AND (&&) and OR (||). + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/buffering/#retryexpression + type: string + type: object + chain: + description: |- + Chain holds the configuration of the chain middleware. + This middleware enables to define reusable combinations of other pieces of middleware. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/chain/ + properties: + middlewares: + description: Middlewares is the list of MiddlewareRef which composes + the chain. + items: + description: MiddlewareRef is a reference to a Middleware resource. + properties: + name: + description: Name defines the name of the referenced Middleware + resource. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Middleware resource. + type: string + required: + - name + type: object + type: array + type: object + circuitBreaker: + description: CircuitBreaker holds the circuit breaker configuration. + properties: + checkPeriod: + anyOf: + - type: integer + - type: string + description: CheckPeriod is the interval between successive checks + of the circuit breaker condition (when in standby state). + x-kubernetes-int-or-string: true + expression: + description: Expression is the condition that triggers the tripped + state. + type: string + fallbackDuration: + anyOf: + - type: integer + - type: string + description: FallbackDuration is the duration for which the circuit + breaker will wait before trying to recover (from a tripped state). + x-kubernetes-int-or-string: true + recoveryDuration: + anyOf: + - type: integer + - type: string + description: RecoveryDuration is the duration for which the circuit + breaker will try to recover (as soon as it is in recovering + state). + x-kubernetes-int-or-string: true + responseCode: + description: ResponseCode is the status code that the circuit + breaker will return while it is in the open state. + type: integer + type: object + compress: + description: |- + Compress holds the compress middleware configuration. + This middleware compresses responses before sending them to the client, using gzip, brotli, or zstd compression. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/compress/ + properties: + defaultEncoding: + description: DefaultEncoding specifies the default encoding if + the `Accept-Encoding` header is not in the request or contains + a wildcard (`*`). + type: string + encodings: + description: Encodings defines the list of supported compression + algorithms. + items: + type: string + type: array + excludedContentTypes: + description: |- + ExcludedContentTypes defines the list of content types to compare the Content-Type header of the incoming requests and responses before compressing. + `application/grpc` is always excluded. + items: + type: string + type: array + includedContentTypes: + description: IncludedContentTypes defines the list of content + types to compare the Content-Type header of the responses before + compressing. + items: + type: string + type: array + minResponseBodyBytes: + description: |- + MinResponseBodyBytes defines the minimum amount of bytes a response body must have to be compressed. + Default: 1024. + type: integer + type: object + contentType: + description: |- + ContentType holds the content-type middleware configuration. + This middleware exists to enable the correct behavior until at least the default one can be changed in a future version. + properties: + autoDetect: + description: |- + AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend, + be automatically set to a value derived from the contents of the response. + Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option. + type: boolean + type: object + digestAuth: + description: |- + DigestAuth holds the digest auth middleware configuration. + This middleware restricts access to your services to known users. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/digestauth/ + properties: + headerField: + description: |- + HeaderField defines a header field to store the authenticated user. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/basicauth/#headerfield + type: string + realm: + description: |- + Realm allows the protected resources on a server to be partitioned into a set of protection spaces, each with its own authentication scheme. + Default: traefik. + type: string + removeHeader: + description: RemoveHeader defines whether to remove the authorization + header before forwarding the request to the backend. + type: boolean + secret: + description: Secret is the name of the referenced Kubernetes Secret + containing user credentials. + type: string + type: object + errors: + description: |- + ErrorPage holds the custom error middleware configuration. + This middleware returns a custom page in lieu of the default, according to configured ranges of HTTP Status codes. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/errorpages/ + properties: + query: + description: |- + Query defines the URL for the error page (hosted by service). + The {status} variable can be used in order to insert the status code in the URL. + type: string + service: + description: |- + Service defines the reference to a Kubernetes Service that will serve the error page. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/errorpages/#service + properties: + healthCheck: + description: Healthcheck defines health checks for ExternalName + services. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent + to the health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname in + the Host header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the + health check endpoint. + type: string + port: + description: Port defines the server URL port for the + health check endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for + the health check endpoint. + type: string + status: + description: Status defines the expected HTTP status code + of the response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + type: object + kind: + description: Kind defines the kind of the Service. + enum: + - Service + - TraefikService + type: string + name: + description: |- + Name defines the name of the referenced Kubernetes Service or TraefikService. + The differentiation between the two is specified in the Kind field. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service or TraefikService. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + passHostHeader: + description: |- + PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service. + By default, passHostHeader is true. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + responseForwarding: + description: ResponseForwarding defines how Traefik forwards + the response from the upstream Kubernetes Service to the + client. + properties: + flushInterval: + description: |- + FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body. + A negative value means to flush immediately after each write to the client. + This configuration is ignored when ReverseProxy recognizes a response as a streaming response; + for such responses, writes are flushed to the client immediately. + Default: 100ms + type: string + type: object + scheme: + description: |- + Scheme defines the scheme to use for the request to the upstream Kubernetes Service. + It defaults to https when Kubernetes Service port is 443, http otherwise. + type: string + serversTransport: + description: |- + ServersTransport defines the name of ServersTransport resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + sticky: + description: |- + Sticky defines the sticky sessions configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#sticky-sessions + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie can + be accessed by client-side APIs, such as JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie can + only be transmitted over an encrypted connection + (i.e. HTTPS). + type: boolean + type: object + type: object + strategy: + description: |- + Strategy defines the load balancing strategy between the servers. + RoundRobin is the only supported value at the moment. + type: string + weight: + description: |- + Weight defines the weight and should only be specified when Name references a TraefikService object + (and to be precise, one that embeds a Weighted Round Robin). + type: integer + required: + - name + type: object + status: + description: |- + Status defines which status or range of statuses should result in an error page. + It can be either a status code as a number (500), + as multiple comma-separated numbers (500,502), + as ranges by separating two codes with a dash (500-599), + or a combination of the two (404,418,500-599). + items: + type: string + type: array + type: object + forwardAuth: + description: |- + ForwardAuth holds the forward auth middleware configuration. + This middleware delegates the request authentication to a Service. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/forwardauth/ + properties: + addAuthCookiesToResponse: + description: AddAuthCookiesToResponse defines the list of cookies + to copy from the authentication server response to the response. + items: + type: string + type: array + address: + description: Address defines the authentication server address. + type: string + authRequestHeaders: + description: |- + AuthRequestHeaders defines the list of the headers to copy from the request to the authentication server. + If not set or empty then all request headers are passed. + items: + type: string + type: array + authResponseHeaders: + description: AuthResponseHeaders defines the list of headers to + copy from the authentication server response and set on forwarded + request, replacing any existing conflicting headers. + items: + type: string + type: array + authResponseHeadersRegex: + description: |- + AuthResponseHeadersRegex defines the regex to match headers to copy from the authentication server response and set on forwarded request, after stripping all headers that match the regex. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/forwardauth/#authresponseheadersregex + type: string + tls: + description: TLS defines the configuration used to secure the + connection to the authentication server. + properties: + caOptional: + description: 'Deprecated: TLS client authentication is a server + side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634).' + type: boolean + caSecret: + description: |- + CASecret is the name of the referenced Kubernetes Secret containing the CA to validate the server certificate. + The CA certificate is extracted from key `tls.ca` or `ca.crt`. + type: string + certSecret: + description: |- + CertSecret is the name of the referenced Kubernetes Secret containing the client certificate. + The client certificate is extracted from the keys `tls.crt` and `tls.key`. + type: string + insecureSkipVerify: + description: InsecureSkipVerify defines whether the server + certificates should be validated. + type: boolean + type: object + trustForwardHeader: + description: 'TrustForwardHeader defines whether to trust (ie: + forward) all X-Forwarded-* headers.' + type: boolean + type: object + grpcWeb: + description: |- + GrpcWeb holds the gRPC web middleware configuration. + This middleware converts a gRPC web request to an HTTP/2 gRPC request. + properties: + allowOrigins: + description: |- + AllowOrigins is a list of allowable origins. + Can also be a wildcard origin "*". + items: + type: string + type: array + type: object + headers: + description: |- + Headers holds the headers middleware configuration. + This middleware manages the requests and responses headers. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/headers/#customrequestheaders + properties: + accessControlAllowCredentials: + description: AccessControlAllowCredentials defines whether the + request can include user credentials. + type: boolean + accessControlAllowHeaders: + description: AccessControlAllowHeaders defines the Access-Control-Request-Headers + values sent in preflight response. + items: + type: string + type: array + accessControlAllowMethods: + description: AccessControlAllowMethods defines the Access-Control-Request-Method + values sent in preflight response. + items: + type: string + type: array + accessControlAllowOriginList: + description: AccessControlAllowOriginList is a list of allowable + origins. Can also be a wildcard origin "*". + items: + type: string + type: array + accessControlAllowOriginListRegex: + description: AccessControlAllowOriginListRegex is a list of allowable + origins written following the Regular Expression syntax (https://golang.org/pkg/regexp/). + items: + type: string + type: array + accessControlExposeHeaders: + description: AccessControlExposeHeaders defines the Access-Control-Expose-Headers + values sent in preflight response. + items: + type: string + type: array + accessControlMaxAge: + description: AccessControlMaxAge defines the time that a preflight + request may be cached. + format: int64 + type: integer + addVaryHeader: + description: AddVaryHeader defines whether the Vary header is + automatically added/updated when the AccessControlAllowOriginList + is set. + type: boolean + allowedHosts: + description: AllowedHosts defines the fully qualified list of + allowed domain names. + items: + type: string + type: array + browserXssFilter: + description: BrowserXSSFilter defines whether to add the X-XSS-Protection + header with the value 1; mode=block. + type: boolean + contentSecurityPolicy: + description: ContentSecurityPolicy defines the Content-Security-Policy + header value. + type: string + contentSecurityPolicyReportOnly: + description: ContentSecurityPolicyReportOnly defines the Content-Security-Policy-Report-Only + header value. + type: string + contentTypeNosniff: + description: ContentTypeNosniff defines whether to add the X-Content-Type-Options + header with the nosniff value. + type: boolean + customBrowserXSSValue: + description: |- + CustomBrowserXSSValue defines the X-XSS-Protection header value. + This overrides the BrowserXssFilter option. + type: string + customFrameOptionsValue: + description: |- + CustomFrameOptionsValue defines the X-Frame-Options header value. + This overrides the FrameDeny option. + type: string + customRequestHeaders: + additionalProperties: + type: string + description: CustomRequestHeaders defines the header names and + values to apply to the request. + type: object + customResponseHeaders: + additionalProperties: + type: string + description: CustomResponseHeaders defines the header names and + values to apply to the response. + type: object + featurePolicy: + description: 'Deprecated: FeaturePolicy option is deprecated, + please use PermissionsPolicy instead.' + type: string + forceSTSHeader: + description: ForceSTSHeader defines whether to add the STS header + even when the connection is HTTP. + type: boolean + frameDeny: + description: FrameDeny defines whether to add the X-Frame-Options + header with the DENY value. + type: boolean + hostsProxyHeaders: + description: HostsProxyHeaders defines the header keys that may + hold a proxied hostname value for the request. + items: + type: string + type: array + isDevelopment: + description: |- + IsDevelopment defines whether to mitigate the unwanted effects of the AllowedHosts, SSL, and STS options when developing. + Usually testing takes place using HTTP, not HTTPS, and on localhost, not your production domain. + If you would like your development environment to mimic production with complete Host blocking, SSL redirects, + and STS headers, leave this as false. + type: boolean + permissionsPolicy: + description: |- + PermissionsPolicy defines the Permissions-Policy header value. + This allows sites to control browser features. + type: string + publicKey: + description: PublicKey is the public key that implements HPKP + to prevent MITM attacks with forged certificates. + type: string + referrerPolicy: + description: |- + ReferrerPolicy defines the Referrer-Policy header value. + This allows sites to control whether browsers forward the Referer header to other sites. + type: string + sslForceHost: + description: 'Deprecated: SSLForceHost option is deprecated, please + use RedirectRegex instead.' + type: boolean + sslHost: + description: 'Deprecated: SSLHost option is deprecated, please + use RedirectRegex instead.' + type: string + sslProxyHeaders: + additionalProperties: + type: string + description: |- + SSLProxyHeaders defines the header keys with associated values that would indicate a valid HTTPS request. + It can be useful when using other proxies (example: "X-Forwarded-Proto": "https"). + type: object + sslRedirect: + description: 'Deprecated: SSLRedirect option is deprecated, please + use EntryPoint redirection or RedirectScheme instead.' + type: boolean + sslTemporaryRedirect: + description: 'Deprecated: SSLTemporaryRedirect option is deprecated, + please use EntryPoint redirection or RedirectScheme instead.' + type: boolean + stsIncludeSubdomains: + description: STSIncludeSubdomains defines whether the includeSubDomains + directive is appended to the Strict-Transport-Security header. + type: boolean + stsPreload: + description: STSPreload defines whether the preload flag is appended + to the Strict-Transport-Security header. + type: boolean + stsSeconds: + description: |- + STSSeconds defines the max-age of the Strict-Transport-Security header. + If set to 0, the header is not set. + format: int64 + type: integer + type: object + inFlightReq: + description: |- + InFlightReq holds the in-flight request middleware configuration. + This middleware limits the number of requests being processed and served concurrently. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/inflightreq/ + properties: + amount: + description: |- + Amount defines the maximum amount of allowed simultaneous in-flight request. + The middleware responds with HTTP 429 Too Many Requests if there are already amount requests in progress (based on the same sourceCriterion strategy). + format: int64 + type: integer + sourceCriterion: + description: |- + SourceCriterion defines what criterion is used to group requests as originating from a common source. + If several strategies are defined at the same time, an error will be raised. + If none are set, the default is to use the requestHost. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/inflightreq/#sourcecriterion + properties: + ipStrategy: + description: |- + IPStrategy holds the IP strategy configuration used by Traefik to determine the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ipallowlist/#ipstrategy + properties: + depth: + description: Depth tells Traefik to use the X-Forwarded-For + header and take the IP located at the depth position + (starting from the right). + type: integer + excludedIPs: + description: ExcludedIPs configures Traefik to scan the + X-Forwarded-For header and select the first IP not in + the list. + items: + type: string + type: array + ipv6Subnet: + description: IPv6Subnet configures Traefik to consider + all IPv6 addresses from the defined subnet as originating + from the same IP. Applies to RemoteAddrStrategy and + DepthStrategy. + type: integer + type: object + requestHeaderName: + description: RequestHeaderName defines the name of the header + used to group incoming requests. + type: string + requestHost: + description: RequestHost defines whether to consider the request + Host as the source. + type: boolean + type: object + type: object + ipAllowList: + description: |- + IPAllowList holds the IP allowlist middleware configuration. + This middleware limits allowed requests based on the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ipallowlist/ + properties: + ipStrategy: + description: |- + IPStrategy holds the IP strategy configuration used by Traefik to determine the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ipallowlist/#ipstrategy + properties: + depth: + description: Depth tells Traefik to use the X-Forwarded-For + header and take the IP located at the depth position (starting + from the right). + type: integer + excludedIPs: + description: ExcludedIPs configures Traefik to scan the X-Forwarded-For + header and select the first IP not in the list. + items: + type: string + type: array + ipv6Subnet: + description: IPv6Subnet configures Traefik to consider all + IPv6 addresses from the defined subnet as originating from + the same IP. Applies to RemoteAddrStrategy and DepthStrategy. + type: integer + type: object + rejectStatusCode: + description: |- + RejectStatusCode defines the HTTP status code used for refused requests. + If not set, the default is 403 (Forbidden). + type: integer + sourceRange: + description: SourceRange defines the set of allowed IPs (or ranges + of allowed IPs by using CIDR notation). + items: + type: string + type: array + type: object + ipWhiteList: + description: 'Deprecated: please use IPAllowList instead.' + properties: + ipStrategy: + description: |- + IPStrategy holds the IP strategy configuration used by Traefik to determine the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ipallowlist/#ipstrategy + properties: + depth: + description: Depth tells Traefik to use the X-Forwarded-For + header and take the IP located at the depth position (starting + from the right). + type: integer + excludedIPs: + description: ExcludedIPs configures Traefik to scan the X-Forwarded-For + header and select the first IP not in the list. + items: + type: string + type: array + ipv6Subnet: + description: IPv6Subnet configures Traefik to consider all + IPv6 addresses from the defined subnet as originating from + the same IP. Applies to RemoteAddrStrategy and DepthStrategy. + type: integer + type: object + sourceRange: + description: SourceRange defines the set of allowed IPs (or ranges + of allowed IPs by using CIDR notation). Required. + items: + type: string + type: array + type: object + passTLSClientCert: + description: |- + PassTLSClientCert holds the pass TLS client cert middleware configuration. + This middleware adds the selected data from the passed client TLS certificate to a header. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/passtlsclientcert/ + properties: + info: + description: Info selects the specific client certificate details + you want to add to the X-Forwarded-Tls-Client-Cert-Info header. + properties: + issuer: + description: Issuer defines the client certificate issuer + details to add to the X-Forwarded-Tls-Client-Cert-Info header. + properties: + commonName: + description: CommonName defines whether to add the organizationalUnit + information into the issuer. + type: boolean + country: + description: Country defines whether to add the country + information into the issuer. + type: boolean + domainComponent: + description: DomainComponent defines whether to add the + domainComponent information into the issuer. + type: boolean + locality: + description: Locality defines whether to add the locality + information into the issuer. + type: boolean + organization: + description: Organization defines whether to add the organization + information into the issuer. + type: boolean + province: + description: Province defines whether to add the province + information into the issuer. + type: boolean + serialNumber: + description: SerialNumber defines whether to add the serialNumber + information into the issuer. + type: boolean + type: object + notAfter: + description: NotAfter defines whether to add the Not After + information from the Validity part. + type: boolean + notBefore: + description: NotBefore defines whether to add the Not Before + information from the Validity part. + type: boolean + sans: + description: Sans defines whether to add the Subject Alternative + Name information from the Subject Alternative Name part. + type: boolean + serialNumber: + description: SerialNumber defines whether to add the client + serialNumber information. + type: boolean + subject: + description: Subject defines the client certificate subject + details to add to the X-Forwarded-Tls-Client-Cert-Info header. + properties: + commonName: + description: CommonName defines whether to add the organizationalUnit + information into the subject. + type: boolean + country: + description: Country defines whether to add the country + information into the subject. + type: boolean + domainComponent: + description: DomainComponent defines whether to add the + domainComponent information into the subject. + type: boolean + locality: + description: Locality defines whether to add the locality + information into the subject. + type: boolean + organization: + description: Organization defines whether to add the organization + information into the subject. + type: boolean + organizationalUnit: + description: OrganizationalUnit defines whether to add + the organizationalUnit information into the subject. + type: boolean + province: + description: Province defines whether to add the province + information into the subject. + type: boolean + serialNumber: + description: SerialNumber defines whether to add the serialNumber + information into the subject. + type: boolean + type: object + type: object + pem: + description: PEM sets the X-Forwarded-Tls-Client-Cert header with + the certificate. + type: boolean + type: object + plugin: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + description: |- + Plugin defines the middleware plugin configuration. + More info: https://doc.traefik.io/traefik/plugins/ + type: object + rateLimit: + description: |- + RateLimit holds the rate limit configuration. + This middleware ensures that services will receive a fair amount of requests, and allows one to define what fair is. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ratelimit/ + properties: + average: + description: |- + Average is the maximum rate, by default in requests/s, allowed for the given source. + It defaults to 0, which means no rate limiting. + The rate is actually defined by dividing Average by Period. So for a rate below 1req/s, + one needs to define a Period larger than a second. + format: int64 + type: integer + burst: + description: |- + Burst is the maximum number of requests allowed to arrive in the same arbitrarily small period of time. + It defaults to 1. + format: int64 + type: integer + period: + anyOf: + - type: integer + - type: string + description: |- + Period, in combination with Average, defines the actual maximum rate, such as: + r = Average / Period. It defaults to a second. + x-kubernetes-int-or-string: true + sourceCriterion: + description: |- + SourceCriterion defines what criterion is used to group requests as originating from a common source. + If several strategies are defined at the same time, an error will be raised. + If none are set, the default is to use the request's remote address field (as an ipStrategy). + properties: + ipStrategy: + description: |- + IPStrategy holds the IP strategy configuration used by Traefik to determine the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/ipallowlist/#ipstrategy + properties: + depth: + description: Depth tells Traefik to use the X-Forwarded-For + header and take the IP located at the depth position + (starting from the right). + type: integer + excludedIPs: + description: ExcludedIPs configures Traefik to scan the + X-Forwarded-For header and select the first IP not in + the list. + items: + type: string + type: array + ipv6Subnet: + description: IPv6Subnet configures Traefik to consider + all IPv6 addresses from the defined subnet as originating + from the same IP. Applies to RemoteAddrStrategy and + DepthStrategy. + type: integer + type: object + requestHeaderName: + description: RequestHeaderName defines the name of the header + used to group incoming requests. + type: string + requestHost: + description: RequestHost defines whether to consider the request + Host as the source. + type: boolean + type: object + type: object + redirectRegex: + description: |- + RedirectRegex holds the redirect regex middleware configuration. + This middleware redirects a request using regex matching and replacement. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/redirectregex/#regex + properties: + permanent: + description: Permanent defines whether the redirection is permanent + (301). + type: boolean + regex: + description: Regex defines the regex used to match and capture + elements from the request URL. + type: string + replacement: + description: Replacement defines how to modify the URL to have + the new target URL. + type: string + type: object + redirectScheme: + description: |- + RedirectScheme holds the redirect scheme middleware configuration. + This middleware redirects requests from a scheme/port to another. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/redirectscheme/ + properties: + permanent: + description: Permanent defines whether the redirection is permanent + (301). + type: boolean + port: + description: Port defines the port of the new URL. + type: string + scheme: + description: Scheme defines the scheme of the new URL. + type: string + type: object + replacePath: + description: |- + ReplacePath holds the replace path middleware configuration. + This middleware replaces the path of the request URL and store the original path in an X-Replaced-Path header. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/replacepath/ + properties: + path: + description: Path defines the path to use as replacement in the + request URL. + type: string + type: object + replacePathRegex: + description: |- + ReplacePathRegex holds the replace path regex middleware configuration. + This middleware replaces the path of a URL using regex matching and replacement. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/replacepathregex/ + properties: + regex: + description: Regex defines the regular expression used to match + and capture the path from the request URL. + type: string + replacement: + description: Replacement defines the replacement path format, + which can include captured variables. + type: string + type: object + retry: + description: |- + Retry holds the retry middleware configuration. + This middleware reissues requests a given number of times to a backend server if that server does not reply. + As soon as the server answers, the middleware stops retrying, regardless of the response status. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/retry/ + properties: + attempts: + description: Attempts defines how many times the request should + be retried. + type: integer + initialInterval: + anyOf: + - type: integer + - type: string + description: |- + InitialInterval defines the first wait time in the exponential backoff series. + The maximum interval is calculated as twice the initialInterval. + If unspecified, requests will be retried immediately. + The value of initialInterval should be provided in seconds or as a valid duration format, + see https://pkg.go.dev/time#ParseDuration. + x-kubernetes-int-or-string: true + type: object + stripPrefix: + description: |- + StripPrefix holds the strip prefix middleware configuration. + This middleware removes the specified prefixes from the URL path. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/stripprefix/ + properties: + forceSlash: + description: |- + Deprecated: ForceSlash option is deprecated, please remove any usage of this option. + ForceSlash ensures that the resulting stripped path is not the empty string, by replacing it with / when necessary. + Default: true. + type: boolean + prefixes: + description: Prefixes defines the prefixes to strip from the request + URL. + items: + type: string + type: array + type: object + stripPrefixRegex: + description: |- + StripPrefixRegex holds the strip prefix regex middleware configuration. + This middleware removes the matching prefixes from the URL path. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/http/stripprefixregex/ + properties: + regex: + description: Regex defines the regular expression to match the + path prefix from the request URL. + items: + type: string + type: array + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_middlewaretcps.yaml b/traefik/crds/traefik.io_middlewaretcps.yaml new file mode 100644 index 000000000..fc23e11b5 --- /dev/null +++ b/traefik/crds/traefik.io_middlewaretcps.yaml @@ -0,0 +1,87 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: middlewaretcps.traefik.io +spec: + group: traefik.io + names: + kind: MiddlewareTCP + listKind: MiddlewareTCPList + plural: middlewaretcps + singular: middlewaretcp + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + MiddlewareTCP is the CRD implementation of a Traefik TCP middleware. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/overview/ + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MiddlewareTCPSpec defines the desired state of a MiddlewareTCP. + properties: + inFlightConn: + description: InFlightConn defines the InFlightConn middleware configuration. + properties: + amount: + description: |- + Amount defines the maximum amount of allowed simultaneous connections. + The middleware closes the connection if there are already amount connections opened. + format: int64 + type: integer + type: object + ipAllowList: + description: |- + IPAllowList defines the IPAllowList middleware configuration. + This middleware accepts/refuses connections based on the client IP. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/tcp/ipallowlist/ + properties: + sourceRange: + description: SourceRange defines the allowed IPs (or ranges of + allowed IPs by using CIDR notation). + items: + type: string + type: array + type: object + ipWhiteList: + description: |- + IPWhiteList defines the IPWhiteList middleware configuration. + This middleware accepts/refuses connections based on the client IP. + Deprecated: please use IPAllowList instead. + More info: https://doc.traefik.io/traefik/v3.2/middlewares/tcp/ipwhitelist/ + properties: + sourceRange: + description: SourceRange defines the allowed IPs (or ranges of + allowed IPs by using CIDR notation). + items: + type: string + type: array + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_serverstransports.yaml b/traefik/crds/traefik.io_serverstransports.yaml new file mode 100644 index 000000000..fe2f129ad --- /dev/null +++ b/traefik/crds/traefik.io_serverstransports.yaml @@ -0,0 +1,139 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: serverstransports.traefik.io +spec: + group: traefik.io + names: + kind: ServersTransport + listKind: ServersTransportList + plural: serverstransports + singular: serverstransport + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ServersTransport is the CRD implementation of a ServersTransport. + If no serversTransport is specified, the default@internal will be used. + The default@internal serversTransport is created from the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#serverstransport_1 + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ServersTransportSpec defines the desired state of a ServersTransport. + properties: + certificatesSecrets: + description: CertificatesSecrets defines a list of secret storing + client certificates for mTLS. + items: + type: string + type: array + disableHTTP2: + description: DisableHTTP2 disables HTTP/2 for connections with backend + servers. + type: boolean + forwardingTimeouts: + description: ForwardingTimeouts defines the timeouts for requests + forwarded to the backend servers. + properties: + dialTimeout: + anyOf: + - type: integer + - type: string + description: DialTimeout is the amount of time to wait until a + connection to a backend server can be established. + x-kubernetes-int-or-string: true + idleConnTimeout: + anyOf: + - type: integer + - type: string + description: IdleConnTimeout is the maximum period for which an + idle HTTP keep-alive connection will remain open before closing + itself. + x-kubernetes-int-or-string: true + pingTimeout: + anyOf: + - type: integer + - type: string + description: PingTimeout is the timeout after which the HTTP/2 + connection will be closed if a response to ping is not received. + x-kubernetes-int-or-string: true + readIdleTimeout: + anyOf: + - type: integer + - type: string + description: ReadIdleTimeout is the timeout after which a health + check using ping frame will be carried out if no frame is received + on the HTTP/2 connection. + x-kubernetes-int-or-string: true + responseHeaderTimeout: + anyOf: + - type: integer + - type: string + description: ResponseHeaderTimeout is the amount of time to wait + for a server's response headers after fully writing the request + (including its body, if any). + x-kubernetes-int-or-string: true + type: object + insecureSkipVerify: + description: InsecureSkipVerify disables SSL certificate verification. + type: boolean + maxIdleConnsPerHost: + description: MaxIdleConnsPerHost controls the maximum idle (keep-alive) + to keep per-host. + type: integer + peerCertURI: + description: PeerCertURI defines the peer cert URI used to match against + SAN URI during the peer certificate verification. + type: string + rootCAsSecrets: + description: RootCAsSecrets defines a list of CA secret used to validate + self-signed certificate. + items: + type: string + type: array + serverName: + description: ServerName defines the server name used to contact the + server. + type: string + spiffe: + description: Spiffe defines the SPIFFE configuration. + properties: + ids: + description: IDs defines the allowed SPIFFE IDs (takes precedence + over the SPIFFE TrustDomain). + items: + type: string + type: array + trustDomain: + description: TrustDomain defines the allowed SPIFFE trust domain. + type: string + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_serverstransporttcps.yaml b/traefik/crds/traefik.io_serverstransporttcps.yaml new file mode 100644 index 000000000..2f24c8474 --- /dev/null +++ b/traefik/crds/traefik.io_serverstransporttcps.yaml @@ -0,0 +1,120 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: serverstransporttcps.traefik.io +spec: + group: traefik.io + names: + kind: ServersTransportTCP + listKind: ServersTransportTCPList + plural: serverstransporttcps + singular: serverstransporttcp + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ServersTransportTCP is the CRD implementation of a TCPServersTransport. + If no tcpServersTransport is specified, a default one named default@internal will be used. + The default@internal tcpServersTransport can be configured in the static configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#serverstransport_3 + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ServersTransportTCPSpec defines the desired state of a ServersTransportTCP. + properties: + dialKeepAlive: + anyOf: + - type: integer + - type: string + description: DialKeepAlive is the interval between keep-alive probes + for an active network connection. If zero, keep-alive probes are + sent with a default value (currently 15 seconds), if supported by + the protocol and operating system. Network protocols or operating + systems that do not support keep-alives ignore this field. If negative, + keep-alive probes are disabled. + x-kubernetes-int-or-string: true + dialTimeout: + anyOf: + - type: integer + - type: string + description: DialTimeout is the amount of time to wait until a connection + to a backend server can be established. + x-kubernetes-int-or-string: true + terminationDelay: + anyOf: + - type: integer + - type: string + description: TerminationDelay defines the delay to wait before fully + terminating the connection, after one connected peer has closed + its writing capability. + x-kubernetes-int-or-string: true + tls: + description: TLS defines the TLS configuration + properties: + certificatesSecrets: + description: CertificatesSecrets defines a list of secret storing + client certificates for mTLS. + items: + type: string + type: array + insecureSkipVerify: + description: InsecureSkipVerify disables TLS certificate verification. + type: boolean + peerCertURI: + description: |- + MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host. + PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification. + type: string + rootCAsSecrets: + description: RootCAsSecrets defines a list of CA secret used to + validate self-signed certificates. + items: + type: string + type: array + serverName: + description: ServerName defines the server name used to contact + the server. + type: string + spiffe: + description: Spiffe defines the SPIFFE configuration. + properties: + ids: + description: IDs defines the allowed SPIFFE IDs (takes precedence + over the SPIFFE TrustDomain). + items: + type: string + type: array + trustDomain: + description: TrustDomain defines the allowed SPIFFE trust + domain. + type: string + type: object + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_tlsoptions.yaml b/traefik/crds/traefik.io_tlsoptions.yaml new file mode 100644 index 000000000..498fc3c8b --- /dev/null +++ b/traefik/crds/traefik.io_tlsoptions.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: tlsoptions.traefik.io +spec: + group: traefik.io + names: + kind: TLSOption + listKind: TLSOptionList + plural: tlsoptions + singular: tlsoption + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + TLSOption is the CRD implementation of a Traefik TLS Option, allowing to configure some parameters of the TLS connection. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#tls-options + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TLSOptionSpec defines the desired state of a TLSOption. + properties: + alpnProtocols: + description: |- + ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#alpn-protocols + items: + type: string + type: array + cipherSuites: + description: |- + CipherSuites defines the list of supported cipher suites for TLS versions up to TLS 1.2. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#cipher-suites + items: + type: string + type: array + clientAuth: + description: ClientAuth defines the server's policy for TLS Client + Authentication. + properties: + clientAuthType: + description: ClientAuthType defines the client authentication + type to apply. + enum: + - NoClientCert + - RequestClientCert + - RequireAnyClientCert + - VerifyClientCertIfGiven + - RequireAndVerifyClientCert + type: string + secretNames: + description: SecretNames defines the names of the referenced Kubernetes + Secret storing certificate details. + items: + type: string + type: array + type: object + curvePreferences: + description: |- + CurvePreferences defines the preferred elliptic curves in a specific order. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#curve-preferences + items: + type: string + type: array + maxVersion: + description: |- + MaxVersion defines the maximum TLS version that Traefik will accept. + Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. + Default: None. + type: string + minVersion: + description: |- + MinVersion defines the minimum TLS version that Traefik will accept. + Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. + Default: VersionTLS10. + type: string + preferServerCipherSuites: + description: |- + PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's. + It is enabled automatically when minVersion or maxVersion is set. + Deprecated: https://github.com/golang/go/issues/45430 + type: boolean + sniStrict: + description: SniStrict defines whether Traefik allows connections + from clients connections that do not specify a server_name extension. + type: boolean + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_tlsstores.yaml b/traefik/crds/traefik.io_tlsstores.yaml new file mode 100644 index 000000000..7eacb770e --- /dev/null +++ b/traefik/crds/traefik.io_tlsstores.yaml @@ -0,0 +1,97 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: tlsstores.traefik.io +spec: + group: traefik.io + names: + kind: TLSStore + listKind: TLSStoreList + plural: tlsstores + singular: tlsstore + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + TLSStore is the CRD implementation of a Traefik TLS Store. + For the time being, only the TLSStore named default is supported. + This means that you cannot have two stores that are named default in different Kubernetes namespaces. + More info: https://doc.traefik.io/traefik/v3.2/https/tls/#certificates-stores + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TLSStoreSpec defines the desired state of a TLSStore. + properties: + certificates: + description: Certificates is a list of secret names, each secret holding + a key/certificate pair to add to the store. + items: + description: Certificate holds a secret name for the TLSStore resource. + properties: + secretName: + description: SecretName is the name of the referenced Kubernetes + Secret to specify the certificate details. + type: string + required: + - secretName + type: object + type: array + defaultCertificate: + description: DefaultCertificate defines the default certificate configuration. + properties: + secretName: + description: SecretName is the name of the referenced Kubernetes + Secret to specify the certificate details. + type: string + required: + - secretName + type: object + defaultGeneratedCert: + description: DefaultGeneratedCert defines the default generated certificate + configuration. + properties: + domain: + description: Domain is the domain definition for the DefaultCertificate. + properties: + main: + description: Main defines the main domain name. + type: string + sans: + description: SANs defines the subject alternative domain names. + items: + type: string + type: array + type: object + resolver: + description: Resolver is the name of the resolver that will be + used to issue the DefaultCertificate. + type: string + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/traefik/crds/traefik.io_traefikservices.yaml b/traefik/crds/traefik.io_traefikservices.yaml new file mode 100644 index 000000000..01e28fc5c --- /dev/null +++ b/traefik/crds/traefik.io_traefikservices.yaml @@ -0,0 +1,644 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: traefikservices.traefik.io +spec: + group: traefik.io + names: + kind: TraefikService + listKind: TraefikServiceList + plural: traefikservices + singular: traefikservice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + TraefikService is the CRD implementation of a Traefik Service. + TraefikService object allows to: + - Apply weight to Services on load-balancing + - Mirror traffic on services + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#kind-traefikservice + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TraefikServiceSpec defines the desired state of a TraefikService. + properties: + mirroring: + description: Mirroring defines the Mirroring service configuration. + properties: + healthCheck: + description: Healthcheck defines health checks for ExternalName + services. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent to + the health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname in the + Host header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the health + check endpoint. + type: string + port: + description: Port defines the server URL port for the health + check endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for the + health check endpoint. + type: string + status: + description: Status defines the expected HTTP status code + of the response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + type: object + kind: + description: Kind defines the kind of the Service. + enum: + - Service + - TraefikService + type: string + maxBodySize: + description: |- + MaxBodySize defines the maximum size allowed for the body of the request. + If the body is larger, the request is not mirrored. + Default value is -1, which means unlimited size. + format: int64 + type: integer + mirrorBody: + description: |- + MirrorBody defines whether the body of the request should be mirrored. + Default value is true. + type: boolean + mirrors: + description: Mirrors defines the list of mirrors where Traefik + will duplicate the traffic. + items: + description: MirrorService holds the mirror configuration. + properties: + healthCheck: + description: Healthcheck defines health checks for ExternalName + services. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent + to the health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname + in the Host header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the + health check endpoint. + type: string + port: + description: Port defines the server URL port for the + health check endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for + the health check endpoint. + type: string + status: + description: Status defines the expected HTTP status + code of the response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + type: object + kind: + description: Kind defines the kind of the Service. + enum: + - Service + - TraefikService + type: string + name: + description: |- + Name defines the name of the referenced Kubernetes Service or TraefikService. + The differentiation between the two is specified in the Kind field. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service or TraefikService. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + passHostHeader: + description: |- + PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service. + By default, passHostHeader is true. + type: boolean + percent: + description: |- + Percent defines the part of the traffic to mirror. + Supported values: 0 to 100. + type: integer + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + responseForwarding: + description: ResponseForwarding defines how Traefik forwards + the response from the upstream Kubernetes Service to the + client. + properties: + flushInterval: + description: |- + FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body. + A negative value means to flush immediately after each write to the client. + This configuration is ignored when ReverseProxy recognizes a response as a streaming response; + for such responses, writes are flushed to the client immediately. + Default: 100ms + type: string + type: object + scheme: + description: |- + Scheme defines the scheme to use for the request to the upstream Kubernetes Service. + It defaults to https when Kubernetes Service port is 443, http otherwise. + type: string + serversTransport: + description: |- + ServersTransport defines the name of ServersTransport resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + sticky: + description: |- + Sticky defines the sticky sessions configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#sticky-sessions + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie + can be accessed by client-side APIs, such as JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie can + only be transmitted over an encrypted connection + (i.e. HTTPS). + type: boolean + type: object + type: object + strategy: + description: |- + Strategy defines the load balancing strategy between the servers. + RoundRobin is the only supported value at the moment. + type: string + weight: + description: |- + Weight defines the weight and should only be specified when Name references a TraefikService object + (and to be precise, one that embeds a Weighted Round Robin). + type: integer + required: + - name + type: object + type: array + name: + description: |- + Name defines the name of the referenced Kubernetes Service or TraefikService. + The differentiation between the two is specified in the Kind field. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service or TraefikService. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + passHostHeader: + description: |- + PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service. + By default, passHostHeader is true. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + responseForwarding: + description: ResponseForwarding defines how Traefik forwards the + response from the upstream Kubernetes Service to the client. + properties: + flushInterval: + description: |- + FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body. + A negative value means to flush immediately after each write to the client. + This configuration is ignored when ReverseProxy recognizes a response as a streaming response; + for such responses, writes are flushed to the client immediately. + Default: 100ms + type: string + type: object + scheme: + description: |- + Scheme defines the scheme to use for the request to the upstream Kubernetes Service. + It defaults to https when Kubernetes Service port is 443, http otherwise. + type: string + serversTransport: + description: |- + ServersTransport defines the name of ServersTransport resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + sticky: + description: |- + Sticky defines the sticky sessions configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#sticky-sessions + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie can be + accessed by client-side APIs, such as JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie can only + be transmitted over an encrypted connection (i.e. HTTPS). + type: boolean + type: object + type: object + strategy: + description: |- + Strategy defines the load balancing strategy between the servers. + RoundRobin is the only supported value at the moment. + type: string + weight: + description: |- + Weight defines the weight and should only be specified when Name references a TraefikService object + (and to be precise, one that embeds a Weighted Round Robin). + type: integer + required: + - name + type: object + weighted: + description: Weighted defines the Weighted Round Robin configuration. + properties: + services: + description: Services defines the list of Kubernetes Service and/or + TraefikService to load-balance, with weight. + items: + description: Service defines an upstream HTTP service to proxy + traffic to. + properties: + healthCheck: + description: Healthcheck defines health checks for ExternalName + services. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent + to the health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname + in the Host header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the + health check endpoint. + type: string + port: + description: Port defines the server URL port for the + health check endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for + the health check endpoint. + type: string + status: + description: Status defines the expected HTTP status + code of the response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + type: object + kind: + description: Kind defines the kind of the Service. + enum: + - Service + - TraefikService + type: string + name: + description: |- + Name defines the name of the referenced Kubernetes Service or TraefikService. + The differentiation between the two is specified in the Kind field. + type: string + namespace: + description: Namespace defines the namespace of the referenced + Kubernetes Service or TraefikService. + type: string + nativeLB: + description: |- + NativeLB controls, when creating the load-balancer, + whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. + The Kubernetes Service itself does load-balance to the pods. + By default, NativeLB is false. + type: boolean + nodePortLB: + description: |- + NodePortLB controls, when creating the load-balancer, + whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. + It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. + By default, NodePortLB is false. + type: boolean + passHostHeader: + description: |- + PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service. + By default, passHostHeader is true. + type: boolean + port: + anyOf: + - type: integer + - type: string + description: |- + Port defines the port of a Kubernetes Service. + This can be a reference to a named port. + x-kubernetes-int-or-string: true + responseForwarding: + description: ResponseForwarding defines how Traefik forwards + the response from the upstream Kubernetes Service to the + client. + properties: + flushInterval: + description: |- + FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body. + A negative value means to flush immediately after each write to the client. + This configuration is ignored when ReverseProxy recognizes a response as a streaming response; + for such responses, writes are flushed to the client immediately. + Default: 100ms + type: string + type: object + scheme: + description: |- + Scheme defines the scheme to use for the request to the upstream Kubernetes Service. + It defaults to https when Kubernetes Service port is 443, http otherwise. + type: string + serversTransport: + description: |- + ServersTransport defines the name of ServersTransport resource to use. + It allows to configure the transport between Traefik and your servers. + Can only be used on a Kubernetes Service. + type: string + sticky: + description: |- + Sticky defines the sticky sessions configuration. + More info: https://doc.traefik.io/traefik/v3.2/routing/services/#sticky-sessions + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie + can be accessed by client-side APIs, such as JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie can + only be transmitted over an encrypted connection + (i.e. HTTPS). + type: boolean + type: object + type: object + strategy: + description: |- + Strategy defines the load balancing strategy between the servers. + RoundRobin is the only supported value at the moment. + type: string + weight: + description: |- + Weight defines the weight and should only be specified when Name references a TraefikService object + (and to be precise, one that embeds a Weighted Round Robin). + type: integer + required: + - name + type: object + type: array + sticky: + description: |- + Sticky defines whether sticky sessions are enabled. + More info: https://doc.traefik.io/traefik/v3.2/routing/providers/kubernetes-crd/#stickiness-and-load-balancing + properties: + cookie: + description: Cookie defines the sticky cookie configuration. + properties: + httpOnly: + description: HTTPOnly defines whether the cookie can be + accessed by client-side APIs, such as JavaScript. + type: boolean + maxAge: + description: |- + MaxAge indicates the number of seconds until the cookie expires. + When set to a negative number, the cookie expires immediately. + When set to zero, the cookie never expires. + type: integer + name: + description: Name defines the Cookie name. + type: string + sameSite: + description: |- + SameSite defines the same site policy. + More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + type: string + secure: + description: Secure defines whether the cookie can only + be transmitted over an encrypted connection (i.e. HTTPS). + type: boolean + type: object + type: object + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true From 2a499fc05f14c239db49b9d07ea4c985326023c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 16 Dec 2024 08:12:34 +0100 Subject: [PATCH 30/44] fix: doc --- traefik/VALUES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/traefik/VALUES.md b/traefik/VALUES.md index 34dd0045e..efcf1f1b9 100644 --- a/traefik/VALUES.md +++ b/traefik/VALUES.md @@ -24,6 +24,10 @@ A Traefik based Kubernetes ingress controller Kubernetes: `>=1.22.0-0` +| Repository | Name | Version | +|------------|------|---------| +| https://traefik.github.io/charts | traefik-crds | 0.0.1 | + ## Values | Key | Type | Default | Description | @@ -320,6 +324,9 @@ Kubernetes: `>=1.22.0-0` | tracing.safeQueryParams | list | `[]` | By default, all query parameters are redacted. Defines the list of query parameters to not redact. | | tracing.sampleRate | string | `nil` | The proportion of requests to trace, specified between 0.0 and 1.0. Default: 1.0. | | tracing.serviceName | string | `nil` | Service name used in selected backend. Default: traefik. | +| traefik-crds.gateway_api | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | +| traefik-crds.hub | string | `"{{- tpl \"and .Values.hub.token .Values.hub.apimanagement.enabled\"' . }}\n"` | | +| traefik-crds.traefik | bool | `true` | Set all the following to false if you want to manage CRDs your-self | | updateStrategy.rollingUpdate.maxSurge | int | `1` | | | updateStrategy.rollingUpdate.maxUnavailable | int | `0` | | | updateStrategy.type | string | `"RollingUpdate"` | Customize updateStrategy of Deployment or DaemonSet | From 1f5ddd50fb85c21e3be157a65a1651c1935d41d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 16 Dec 2024 08:14:00 +0100 Subject: [PATCH 31/44] fix: rename gateway api + add enabled flag --- README.md | 2 +- traefik-crds/VALUES.md | 3 +- .../gateway-standard-install.yaml | 0 traefik-crds/kustomization.yaml | 16 + traefik-crds/templates/crds.yaml | 4 +- traefik-crds/tests/crds_test.yaml | 4 +- traefik-crds/values.schema.json | 5 +- traefik-crds/values.yaml | 3 +- traefik/Chart.yaml | 2 +- traefik/VALUES.md | 5 + .../crds/gateway-standard-install.yaml | 0 .../hub.traefik.io_accesscontrolpolicies.yaml | 368 ++++++++++++++++++ traefik/crds/hub.traefik.io_aiservices.yaml | 245 ++++++++++++ traefik/crds/hub.traefik.io_apiaccesses.yaml | 190 +++++++++ traefik/crds/hub.traefik.io_apibundles.yaml | 125 ++++++ .../crds/hub.traefik.io_apicatalogitems.yaml | 184 +++++++++ traefik/crds/hub.traefik.io_apiplans.yaml | 103 +++++ traefik/crds/hub.traefik.io_apiportals.yaml | 139 +++++++ .../crds/hub.traefik.io_apiratelimits.yaml | 166 ++++++++ traefik/crds/hub.traefik.io_apis.yaml | 190 +++++++++ traefik/crds/hub.traefik.io_apiversions.yaml | 194 +++++++++ .../hub.traefik.io_managedsubscriptions.yaml | 204 ++++++++++ traefik/values.schema.json | 17 +- traefik/values.yaml | 7 +- 24 files changed, 2162 insertions(+), 14 deletions(-) rename traefik-crds/crds-files/{gateway_api => gatewayAPI}/gateway-standard-install.yaml (100%) rename traefik-crds/crds-files/gateway_api/gateway-standard-install-v1.2.0.yaml => traefik/crds/gateway-standard-install.yaml (100%) create mode 100644 traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml create mode 100644 traefik/crds/hub.traefik.io_aiservices.yaml create mode 100644 traefik/crds/hub.traefik.io_apiaccesses.yaml create mode 100644 traefik/crds/hub.traefik.io_apibundles.yaml create mode 100644 traefik/crds/hub.traefik.io_apicatalogitems.yaml create mode 100644 traefik/crds/hub.traefik.io_apiplans.yaml create mode 100644 traefik/crds/hub.traefik.io_apiportals.yaml create mode 100644 traefik/crds/hub.traefik.io_apiratelimits.yaml create mode 100644 traefik/crds/hub.traefik.io_apis.yaml create mode 100644 traefik/crds/hub.traefik.io_apiversions.yaml create mode 100644 traefik/crds/hub.traefik.io_managedsubscriptions.yaml diff --git a/README.md b/README.md index 69b738df7..3d7293aa7 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ If you still want to manage CRDs your self, it can be opt-out: ```bash # Upgrade Traefik and skip all CRDs installation -helm upgrade traefik traefik/traefik --set traefik-crds.traefik=false --set traefik-crds.hub=false --set traefik-crds.gateway_api=false +helm upgrade traefik traefik/traefik --set traefik-crds.enabled=true --set traefik-crds.traefik=false --set traefik-crds.hub=false --set traefik-crds.gatewayAPI=false ``` ### Upgrade up to 27.X diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index 68d56e701..a7ddb2a3f 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -29,7 +29,8 @@ Kubernetes: `>=1.22.0-0` | Key | Type | Default | Description | |-----|------|---------|-------------| | deleteOnUninstall | bool | `false` | | -| gateway_api | bool | `false` | | +| enabled | bool | `true` | | +| gatewayAPI | bool | `false` | | | global | string | `nil` | | | hub | bool | `false` | | | traefik | bool | `false` | | diff --git a/traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml b/traefik-crds/crds-files/gatewayAPI/gateway-standard-install.yaml similarity index 100% rename from traefik-crds/crds-files/gateway_api/gateway-standard-install.yaml rename to traefik-crds/crds-files/gatewayAPI/gateway-standard-install.yaml diff --git a/traefik-crds/kustomization.yaml b/traefik-crds/kustomization.yaml index a615713e7..805135a05 100644 --- a/traefik-crds/kustomization.yaml +++ b/traefik-crds/kustomization.yaml @@ -2,6 +2,7 @@ kind: Kustomization apiVersion: kustomize.config.k8s.io/v1beta1 resources: +<<<<<<< HEAD # curl -o crds-files/gateway_api/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml - crds-files/gateway_api/gateway-standard-install.yaml - crds-files/hub.traefik.io_accesscontrolpolicies.yaml @@ -15,6 +16,21 @@ resources: - crds-files/hub.traefik.io_apis.yaml - crds-files/hub.traefik.io_apiversions.yaml - crds-files/hub.traefik.io_managedsubscriptions.yaml +======= + # curl -o gateway-standard-install-v1.2.0.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml + - crds-files/gatewayAPI/gateway-standard-install-v1.2.0.yaml + - crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml + - crds-files/hub/hub.traefik.io_aiservices.yaml + - crds-files/hub/hub.traefik.io_apiaccesses.yaml + - crds-files/hub/hub.traefik.io_apibundles.yaml + - crds-files/hub/hub.traefik.io_apicatalogitems.yaml + - crds-files/hub/hub.traefik.io_apiplans.yaml + - crds-files/hub/hub.traefik.io_apiportals.yaml + - crds-files/hub/hub.traefik.io_apiratelimits.yaml + - crds-files/hub/hub.traefik.io_apis.yaml + - crds-files/hub/hub.traefik.io_apiversions.yaml + - crds-files/hub/hub.traefik.io_managedsubscriptions.yaml +>>>>>>> b296543 (fix: rename gateway api + add enabled flag) - crds-files/traefik/traefik.io_ingressroutes.yaml - crds-files/traefik/traefik.io_ingressroutetcps.yaml - crds-files/traefik/traefik.io_ingressrouteudps.yaml diff --git a/traefik-crds/templates/crds.yaml b/traefik-crds/templates/crds.yaml index 9440dd591..859453ae7 100644 --- a/traefik-crds/templates/crds.yaml +++ b/traefik-crds/templates/crds.yaml @@ -6,6 +6,6 @@ {{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/hub/*.yaml") }} {{- end }} -{{- if eq (.Values.gateway_api | toString) "true" -}} -{{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/gateway_api/*.yaml") }} +{{- if eq (.Values.gatewayAPI | toString) "true" -}} +{{ include "traefik-crds.render-crds" (dict "scope" . "path" "crds-files/gatewayAPI/*.yaml") }} {{- end }} diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml index ce1ce07c1..c9dbe2ec6 100644 --- a/traefik-crds/tests/crds_test.yaml +++ b/traefik-crds/tests/crds_test.yaml @@ -45,7 +45,7 @@ tests: - it: should have all Gateway API crds set: - gateway_api: true + gatewayAPI: true asserts: - hasDocuments: count: 5 @@ -63,7 +63,7 @@ tests: - it: should have all Gateway API crds without helm keep resource policy set: - gateway_api: true + gatewayAPI: true deleteOnUninstall: true asserts: - hasDocuments: diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index 99668a020..c79af9218 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -7,7 +7,10 @@ "deleteOnUninstall": { "type": "boolean" }, - "gateway_api": { + "enabled": { + "type": "boolean" + }, + "gatewayAPI": { "default": false, "type": [ "string", diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index bc5f1b94f..35b12a591 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,5 +1,6 @@ global: # @schema type:[object, null]; additionalProperties: true +enabled: true traefik: false -gateway_api: false # @schema type:[string, boolean]; default: false +gatewayAPI: false # @schema type:[string, boolean]; default: false hub: false # @schema type:[string, boolean]; default: false deleteOnUninstall: false diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 827dcd369..55c0c6896 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -31,4 +31,4 @@ dependencies: - name: traefik-crds version: 0.0.1 repository: https://traefik.github.io/charts - condition: or traefik-crds.traefik traefik-crds.hub traefik-crds.gateway_api + condition: traefik-crds.enabled diff --git a/traefik/VALUES.md b/traefik/VALUES.md index efcf1f1b9..41df7427e 100644 --- a/traefik/VALUES.md +++ b/traefik/VALUES.md @@ -321,10 +321,15 @@ Kubernetes: `>=1.22.0-0` | tracing.otlp.http.tls.cert | string | `""` | The path to the public certificate. When using this option, setting the key option is required. | | tracing.otlp.http.tls.insecureSkipVerify | bool | `false` | When set to true, the TLS connection accepts any certificate presented by the server regardless of the hostnames it covers. | | tracing.otlp.http.tls.key | string | `""` | The path to the private key. When using this option, setting the cert option is required. | +<<<<<<< HEAD | tracing.safeQueryParams | list | `[]` | By default, all query parameters are redacted. Defines the list of query parameters to not redact. | | tracing.sampleRate | string | `nil` | The proportion of requests to trace, specified between 0.0 and 1.0. Default: 1.0. | | tracing.serviceName | string | `nil` | Service name used in selected backend. Default: traefik. | | traefik-crds.gateway_api | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | +======= +| traefik-crds.enabled | bool | `false` | Set it to true to opt-in CRD management | +| traefik-crds.gatewayAPI | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | +>>>>>>> b296543 (fix: rename gateway api + add enabled flag) | traefik-crds.hub | string | `"{{- tpl \"and .Values.hub.token .Values.hub.apimanagement.enabled\"' . }}\n"` | | | traefik-crds.traefik | bool | `true` | Set all the following to false if you want to manage CRDs your-self | | updateStrategy.rollingUpdate.maxSurge | int | `1` | | diff --git a/traefik-crds/crds-files/gateway_api/gateway-standard-install-v1.2.0.yaml b/traefik/crds/gateway-standard-install.yaml similarity index 100% rename from traefik-crds/crds-files/gateway_api/gateway-standard-install-v1.2.0.yaml rename to traefik/crds/gateway-standard-install.yaml diff --git a/traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml b/traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml new file mode 100644 index 000000000..821f969b6 --- /dev/null +++ b/traefik/crds/hub.traefik.io_accesscontrolpolicies.yaml @@ -0,0 +1,368 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: accesscontrolpolicies.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: AccessControlPolicy + listKind: AccessControlPolicyList + plural: accesscontrolpolicies + singular: accesscontrolpolicy + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AccessControlPolicy defines an access control policy. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AccessControlPolicySpec configures an access control policy. + properties: + apiKey: + description: AccessControlPolicyAPIKey configure an APIKey control + policy. + properties: + forwardHeaders: + additionalProperties: + type: string + description: ForwardHeaders instructs the middleware to forward + key metadata as header values upon successful authentication. + type: object + keySource: + description: KeySource defines how to extract API keys from requests. + properties: + cookie: + description: Cookie is the name of a cookie. + type: string + header: + description: Header is the name of a header. + type: string + headerAuthScheme: + description: |- + HeaderAuthScheme sets an optional auth scheme when Header is set to "Authorization". + If set, this scheme is removed from the token, and all requests not including it are dropped. + type: string + query: + description: Query is the name of a query parameter. + type: string + type: object + keys: + description: Keys define the set of authorized keys to access + a protected resource. + items: + description: AccessControlPolicyAPIKeyKey defines an API key. + properties: + id: + description: ID is the unique identifier of the key. + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds arbitrary metadata for this + key, can be used by ForwardHeaders. + type: object + value: + description: Value is the SHAKE-256 hash (using 64 bytes) + of the API key. + type: string + required: + - id + - value + type: object + type: array + required: + - keySource + type: object + basicAuth: + description: AccessControlPolicyBasicAuth holds the HTTP basic authentication + configuration. + properties: + forwardUsernameHeader: + type: string + realm: + type: string + stripAuthorizationHeader: + type: boolean + users: + items: + type: string + type: array + type: object + jwt: + description: AccessControlPolicyJWT configures a JWT access control + policy. + properties: + claims: + type: string + forwardHeaders: + additionalProperties: + type: string + type: object + jwksFile: + type: string + jwksUrl: + type: string + publicKey: + type: string + signingSecret: + type: string + signingSecretBase64Encoded: + type: boolean + stripAuthorizationHeader: + type: boolean + tokenQueryKey: + type: string + type: object + oAuthIntro: + description: AccessControlOAuthIntro configures an OAuth 2.0 Token + Introspection access control policy. + properties: + claims: + type: string + clientConfig: + description: AccessControlOAuthIntroClientConfig configures the + OAuth 2.0 client for issuing token introspection requests. + properties: + headers: + additionalProperties: + type: string + description: Headers to set when sending requests to the Authorization + Server. + type: object + maxRetries: + default: 3 + description: MaxRetries defines the number of retries for + introspection requests. + type: integer + timeoutSeconds: + default: 5 + description: TimeoutSeconds configures the maximum amount + of seconds to wait before giving up on requests. + type: integer + tls: + description: TLS configures TLS communication with the Authorization + Server. + properties: + ca: + description: CA sets the CA bundle used to sign the Authorization + Server certificate. + type: string + insecureSkipVerify: + description: |- + InsecureSkipVerify skips the Authorization Server certificate validation. + For testing purposes only, do not use in production. + type: boolean + type: object + tokenTypeHint: + description: |- + TokenTypeHint is a hint to pass to the Authorization Server. + See https://tools.ietf.org/html/rfc7662#section-2.1 for more information. + type: string + url: + description: URL of the Authorization Server. + type: string + required: + - url + type: object + forwardHeaders: + additionalProperties: + type: string + type: object + tokenSource: + description: |- + TokenSource describes how to extract tokens from HTTP requests. + If multiple sources are set, the order is the following: header > query > cookie. + properties: + cookie: + description: Cookie is the name of a cookie. + type: string + header: + description: Header is the name of a header. + type: string + headerAuthScheme: + description: |- + HeaderAuthScheme sets an optional auth scheme when Header is set to "Authorization". + If set, this scheme is removed from the token, and all requests not including it are dropped. + type: string + query: + description: Query is the name of a query parameter. + type: string + type: object + required: + - clientConfig + - tokenSource + type: object + oidc: + description: AccessControlPolicyOIDC holds the OIDC authentication + configuration. + properties: + authParams: + additionalProperties: + type: string + type: object + claims: + type: string + clientId: + type: string + disableAuthRedirectionPaths: + items: + type: string + type: array + forwardHeaders: + additionalProperties: + type: string + type: object + issuer: + type: string + logoutUrl: + type: string + redirectUrl: + type: string + scopes: + items: + type: string + type: array + secret: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which the + secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + session: + description: Session holds session configuration. + properties: + domain: + type: string + path: + type: string + refresh: + type: boolean + sameSite: + type: string + secure: + type: boolean + type: object + stateCookie: + description: StateCookie holds state cookie configuration. + properties: + domain: + type: string + path: + type: string + sameSite: + type: string + secure: + type: boolean + type: object + type: object + oidcGoogle: + description: AccessControlPolicyOIDCGoogle holds the Google OIDC authentication + configuration. + properties: + authParams: + additionalProperties: + type: string + type: object + clientId: + type: string + emails: + description: Emails are the allowed emails to connect. + items: + type: string + minItems: 1 + type: array + forwardHeaders: + additionalProperties: + type: string + type: object + logoutUrl: + type: string + redirectUrl: + type: string + secret: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which the + secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + session: + description: Session holds session configuration. + properties: + domain: + type: string + path: + type: string + refresh: + type: boolean + sameSite: + type: string + secure: + type: boolean + type: object + stateCookie: + description: StateCookie holds state cookie configuration. + properties: + domain: + type: string + path: + type: string + sameSite: + type: string + secure: + type: boolean + type: object + type: object + type: object + status: + description: The current status of this access control policy. + properties: + specHash: + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_aiservices.yaml b/traefik/crds/hub.traefik.io_aiservices.yaml new file mode 100644 index 000000000..9fc481387 --- /dev/null +++ b/traefik/crds/hub.traefik.io_aiservices.yaml @@ -0,0 +1,245 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: aiservices.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: AIService + listKind: AIServiceList + plural: aiservices + singular: aiservice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AIService is a Kubernetes-like Service to interact with a text-based + LLM provider. It defines the parameters and credentials required to interact + with various LLM providers. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this AIService. + properties: + anthropic: + description: Anthropic configures Anthropic backend. + properties: + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + token: + type: string + required: + - token + type: object + azureOpenai: + description: AzureOpenAI configures AzureOpenAI. + properties: + apiKey: + type: string + baseUrl: + type: string + deploymentName: + type: string + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + required: + - apiKey + - baseUrl + - deploymentName + type: object + bedrock: + description: Bedrock configures Bedrock backend. + properties: + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + region: + type: string + systemMessage: + type: boolean + type: object + cohere: + description: Cohere configures Cohere backend. + properties: + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + token: + type: string + required: + - token + type: object + gemini: + description: Gemini configures Gemini backend. + properties: + apiKey: + type: string + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + required: + - apiKey + type: object + mistral: + description: Mistral configures Mistral AI backend. + properties: + apiKey: + type: string + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + required: + - apiKey + type: object + ollama: + description: Ollama configures Ollama backend. + properties: + baseUrl: + type: string + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + required: + - baseUrl + type: object + openai: + description: OpenAI configures OpenAI. + properties: + model: + type: string + params: + description: Params holds the LLM hyperparameters. + properties: + frequencyPenalty: + type: number + maxTokens: + type: integer + presencePenalty: + type: number + temperature: + type: number + topP: + type: number + type: object + token: + type: string + required: + - token + type: object + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apiaccesses.yaml b/traefik/crds/hub.traefik.io_apiaccesses.yaml new file mode 100644 index 000000000..fef19fdbc --- /dev/null +++ b/traefik/crds/hub.traefik.io_apiaccesses.yaml @@ -0,0 +1,190 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apiaccesses.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIAccess + listKind: APIAccessList + plural: apiaccesses + singular: apiaccess + scope: Namespaced + versions: + - deprecated: true + deprecationWarning: APIAccess is deprecated in favor of APICatalogItems and ManagedSubscription + name: v1alpha1 + schema: + openAPIV3Schema: + description: APIAccess defines who can access to a set of APIs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIAccess. + properties: + apiBundles: + description: |- + APIBundles defines a set of APIBundle that will be accessible to the configured audience. + Multiple APIAccesses can select the same APIBundles. + items: + description: APIBundleReference references an APIBundle. + properties: + name: + description: Name of the APIBundle. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apiBundles + rule: self.all(x, self.exists_one(y, x.name == y.name)) + apiPlan: + description: APIPlan defines which APIPlan will be used. + properties: + name: + description: Name of the APIPlan. + maxLength: 253 + type: string + required: + - name + type: object + apiSelector: + description: |- + APISelector selects the APIs that will be accessible to the configured audience. + Multiple APIAccesses can select the same set of APIs. + This field is optional and follows standard label selector semantics. + An empty APISelector matches any API. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + apis: + description: |- + APIs defines a set of APIs that will be accessible to the configured audience. + Multiple APIAccesses can select the same APIs. + When combined with APISelector, this set of APIs is appended to the matching APIs. + items: + description: APIReference references an API. + properties: + name: + description: Name of the API. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apis + rule: self.all(x, self.exists_one(y, x.name == y.name)) + everyone: + description: Everyone indicates that all users will have access to + the selected APIs. + type: boolean + groups: + description: Groups are the consumer groups that will gain access + to the selected APIs. + items: + type: string + type: array + operationFilter: + description: |- + OperationFilter specifies the allowed operations on APIs and APIVersions. + If not set, all operations are available. + An empty OperationFilter prohibits all operations. + properties: + include: + description: Include defines the names of OperationSets that will + be accessible. + items: + type: string + maxItems: 100 + type: array + type: object + weight: + description: Weight specifies the evaluation order of the plan. + type: integer + x-kubernetes-validations: + - message: must be a positive number + rule: self >= 0 + type: object + x-kubernetes-validations: + - message: groups and everyone are mutually exclusive + rule: '(has(self.everyone) && has(self.groups)) ? !(self.everyone && + self.groups.size() > 0) : true' + status: + description: The current status of this APIAccess. + properties: + hash: + description: Hash is a hash representing the APIAccess. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apibundles.yaml b/traefik/crds/hub.traefik.io_apibundles.yaml new file mode 100644 index 000000000..a45a0b137 --- /dev/null +++ b/traefik/crds/hub.traefik.io_apibundles.yaml @@ -0,0 +1,125 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apibundles.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIBundle + listKind: APIBundleList + plural: apibundles + singular: apibundle + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: APIBundle defines a set of APIs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIBundle. + properties: + apiSelector: + description: |- + APISelector selects the APIs that will be accessible to the configured audience. + Multiple APIBundles can select the same set of APIs. + This field is optional and follows standard label selector semantics. + An empty APISelector matches any API. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + apis: + description: |- + APIs defines a set of APIs that will be accessible to the configured audience. + Multiple APIBundles can select the same APIs. + When combined with APISelector, this set of APIs is appended to the matching APIs. + items: + description: APIReference references an API. + properties: + name: + description: Name of the API. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apis + rule: self.all(x, self.exists_one(y, x.name == y.name)) + type: object + status: + description: The current status of this APIBundle. + properties: + hash: + description: Hash is a hash representing the APIBundle. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apicatalogitems.yaml b/traefik/crds/hub.traefik.io_apicatalogitems.yaml new file mode 100644 index 000000000..387e72aa4 --- /dev/null +++ b/traefik/crds/hub.traefik.io_apicatalogitems.yaml @@ -0,0 +1,184 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apicatalogitems.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APICatalogItem + listKind: APICatalogItemList + plural: apicatalogitems + singular: apicatalogitem + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: APICatalogItem defines APIs that will be part of the API catalog + on the portal. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APICatalogItem. + properties: + apiBundles: + description: |- + APIBundles defines a set of APIBundle that will be visible to the configured audience. + Multiple APICatalogItem can select the same APIBundles. + items: + description: APIBundleReference references an APIBundle. + properties: + name: + description: Name of the APIBundle. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apiBundles + rule: self.all(x, self.exists_one(y, x.name == y.name)) + apiPlan: + description: |- + APIPlan defines which APIPlan will be available. + If multiple APICatalogItem specify the same API with different APIPlan, the API consumer will be able to pick + a plan from this list. + properties: + name: + description: Name of the APIPlan. + maxLength: 253 + type: string + required: + - name + type: object + apiSelector: + description: |- + APISelector selects the APIs that will be visible to the configured audience. + Multiple APICatalogItem can select the same set of APIs. + This field is optional and follows standard label selector semantics. + An empty APISelector matches any API. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + apis: + description: |- + APIs defines a set of APIs that will be visible to the configured audience. + Multiple APICatalogItem can select the same APIs. + When combined with APISelector, this set of APIs is appended to the matching APIs. + items: + description: APIReference references an API. + properties: + name: + description: Name of the API. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apis + rule: self.all(x, self.exists_one(y, x.name == y.name)) + everyone: + description: Everyone indicates that all users will see these APIs. + type: boolean + groups: + description: Groups are the consumer groups that will see the APIs. + items: + type: string + type: array + operationFilter: + description: |- + OperationFilter specifies the visible operations on APIs and APIVersions. + If not set, all operations are available. + An empty OperationFilter prohibits all operations. + properties: + include: + description: Include defines the names of OperationSets that will + be accessible. + items: + type: string + maxItems: 100 + type: array + type: object + type: object + x-kubernetes-validations: + - message: groups and everyone are mutually exclusive + rule: '(has(self.everyone) && has(self.groups)) ? !(self.everyone && + self.groups.size() > 0) : true' + status: + description: The current status of this APICatalogItem. + properties: + hash: + description: Hash is a hash representing the APICatalogItem. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apiplans.yaml b/traefik/crds/hub.traefik.io_apiplans.yaml new file mode 100644 index 000000000..92e1b9b5c --- /dev/null +++ b/traefik/crds/hub.traefik.io_apiplans.yaml @@ -0,0 +1,103 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apiplans.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIPlan + listKind: APIPlanList + plural: apiplans + singular: apiplan + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: APIPlan defines API Plan policy. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIPlan. + properties: + description: + description: Description describes the plan. + type: string + quota: + description: Quota defines the quota policy. + properties: + limit: + description: Limit is the maximum number of token in the bucket. + type: integer + x-kubernetes-validations: + - message: must be a positive number + rule: self >= 0 + period: + description: Period is the unit of time for the Limit. + format: duration + type: string + x-kubernetes-validations: + - message: must be between 1s and 9999h + rule: self >= duration('1s') && self <= duration('9999h') + required: + - limit + type: object + rateLimit: + description: RateLimit defines the rate limit policy. + properties: + limit: + description: Limit is the maximum number of token in the bucket. + type: integer + x-kubernetes-validations: + - message: must be a positive number + rule: self >= 0 + period: + description: Period is the unit of time for the Limit. + format: duration + type: string + x-kubernetes-validations: + - message: must be between 1s and 1h + rule: self >= duration('1s') && self <= duration('1h') + required: + - limit + type: object + title: + description: Title is the human-readable name of the plan. + type: string + required: + - title + type: object + status: + description: The current status of this APIPlan. + properties: + hash: + description: Hash is a hash representing the APIPlan. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apiportals.yaml b/traefik/crds/hub.traefik.io_apiportals.yaml new file mode 100644 index 000000000..bc0417016 --- /dev/null +++ b/traefik/crds/hub.traefik.io_apiportals.yaml @@ -0,0 +1,139 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apiportals.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIPortal + listKind: APIPortalList + plural: apiportals + singular: apiportal + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: APIPortal defines a developer portal for accessing the documentation + of APIs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIPortal. + properties: + description: + description: Description of the APIPortal. + type: string + title: + description: Title is the public facing name of the APIPortal. + type: string + trustedUrls: + description: TrustedURLs are the urls that are trusted by the OAuth + 2.0 authorization server. + items: + type: string + maxItems: 1 + minItems: 1 + type: array + x-kubernetes-validations: + - message: must be a valid URLs + rule: self.all(x, isURL(x)) + ui: + description: UI holds the UI customization options. + properties: + logoUrl: + description: LogoURL is the public URL of the logo. + type: string + type: object + required: + - trustedUrls + type: object + status: + description: The current status of this APIPortal. + properties: + hash: + description: Hash is a hash representing the APIPortal. + type: string + oidc: + description: OIDC is the OIDC configuration for accessing the exposed + APIPortal WebUI. + properties: + clientId: + description: ClientID is the OIDC ClientID for accessing the exposed + APIPortal WebUI. + type: string + companyClaim: + description: CompanyClaim is the name of the JWT claim containing + the user company. + type: string + emailClaim: + description: EmailClaim is the name of the JWT claim containing + the user email. + type: string + firstnameClaim: + description: FirstnameClaim is the name of the JWT claim containing + the user firstname. + type: string + generic: + description: Generic indicates whether or not the APIPortal authentication + relies on Generic OIDC. + type: boolean + groupsClaim: + description: GroupsClaim is the name of the JWT claim containing + the user groups. + type: string + issuer: + description: Issuer is the OIDC issuer for accessing the exposed + APIPortal WebUI. + type: string + lastnameClaim: + description: LastnameClaim is the name of the JWT claim containing + the user lastname. + type: string + scopes: + description: Scopes is the OIDC scopes for getting user attributes + during the authentication to the exposed APIPortal WebUI. + type: string + secretName: + description: SecretName is the name of the secret containing the + OIDC ClientSecret for accessing the exposed APIPortal WebUI. + type: string + syncedAttributes: + description: SyncedAttributes configure the user attributes to + sync. + items: + type: string + type: array + userIdClaim: + description: UserIDClaim is the name of the JWT claim containing + the user ID. + type: string + type: object + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apiratelimits.yaml b/traefik/crds/hub.traefik.io_apiratelimits.yaml new file mode 100644 index 000000000..8e328d3c5 --- /dev/null +++ b/traefik/crds/hub.traefik.io_apiratelimits.yaml @@ -0,0 +1,166 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apiratelimits.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIRateLimit + listKind: APIRateLimitList + plural: apiratelimits + singular: apiratelimit + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: APIRateLimit defines how group of consumers are rate limited + on a set of APIs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIRateLimit. + properties: + apiSelector: + description: |- + APISelector selects the APIs that will be rate limited. + Multiple APIRateLimits can select the same set of APIs. + This field is optional and follows standard label selector semantics. + An empty APISelector matches any API. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + apis: + description: |- + APIs defines a set of APIs that will be rate limited. + Multiple APIRateLimits can select the same APIs. + When combined with APISelector, this set of APIs is appended to the matching APIs. + items: + description: APIReference references an API. + properties: + name: + description: Name of the API. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apis + rule: self.all(x, self.exists_one(y, x.name == y.name)) + everyone: + description: |- + Everyone indicates that all users will, by default, be rate limited with this configuration. + If an APIRateLimit explicitly target a group, the default rate limit will be ignored. + type: boolean + groups: + description: |- + Groups are the consumer groups that will be rate limited. + Multiple APIRateLimits can target the same set of consumer groups, the most restrictive one applies. + When a consumer belongs to multiple groups, the least restrictive APIRateLimit applies. + items: + type: string + type: array + limit: + description: Limit is the maximum number of token in the bucket. + type: integer + x-kubernetes-validations: + - message: must be a positive number + rule: self >= 0 + period: + description: Period is the unit of time for the Limit. + format: duration + type: string + x-kubernetes-validations: + - message: must be between 1s and 1h + rule: self >= duration('1s') && self <= duration('1h') + strategy: + description: |- + Strategy defines how the bucket state will be synchronized between the different Traefik Hub instances. + It can be, either "local" or "distributed". + enum: + - local + - distributed + type: string + required: + - limit + type: object + x-kubernetes-validations: + - message: groups and everyone are mutually exclusive + rule: '(has(self.everyone) && has(self.groups)) ? !(self.everyone && + self.groups.size() > 0) : true' + status: + description: The current status of this APIRateLimit. + properties: + hash: + description: Hash is a hash representing the APIRateLimit. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apis.yaml b/traefik/crds/hub.traefik.io_apis.yaml new file mode 100644 index 000000000..a7b9e5e60 --- /dev/null +++ b/traefik/crds/hub.traefik.io_apis.yaml @@ -0,0 +1,190 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apis.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: API + listKind: APIList + plural: apis + singular: api + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + API defines an HTTP interface that is exposed to external clients. It specifies the supported versions + and provides instructions for accessing its documentation. Once instantiated, an API object is associated + with an Ingress, IngressRoute, or HTTPRoute resource, enabling the exposure of the described API to the outside world. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: APISpec describes the API. + properties: + openApiSpec: + description: OpenAPISpec defines the API contract as an OpenAPI specification. + properties: + operationSets: + description: OperationSets defines the sets of operations to be + referenced for granular filtering in APIAccesses. + items: + description: |- + OperationSet gives a name to a set of matching OpenAPI operations. + This set of operations can then be referenced for granular filtering in APIAccesses. + properties: + matchers: + description: Matchers defines a list of alternative rules + for matching OpenAPI operations. + items: + description: OperationMatcher defines criteria for matching + an OpenAPI operation. + minProperties: 1 + properties: + methods: + description: Methods specifies the HTTP methods to + be included for selection. + items: + type: string + maxItems: 10 + type: array + path: + description: Path specifies the exact path of the + operations to select. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + pathPrefix: + description: PathPrefix specifies the path prefix + of the operations to select. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + pathRegex: + description: PathRegex specifies a regular expression + pattern for matching operations based on their paths. + type: string + type: object + x-kubernetes-validations: + - message: path, pathPrefix and pathRegex are mutually + exclusive + rule: '[has(self.path), has(self.pathPrefix), has(self.pathRegex)].filter(x, + x).size() <= 1' + maxItems: 100 + minItems: 1 + type: array + name: + description: Name is the name of the OperationSet to reference + in APIAccesses. + maxLength: 253 + type: string + required: + - matchers + - name + type: object + maxItems: 100 + type: array + override: + description: Override holds data used to override OpenAPI specification. + properties: + servers: + items: + properties: + url: + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + required: + - url + type: object + maxItems: 100 + minItems: 1 + type: array + required: + - servers + type: object + path: + description: |- + Path specifies the endpoint path within the Kubernetes Service where the OpenAPI specification can be obtained. + The Service queried is determined by the associated Ingress, IngressRoute, or HTTPRoute resource to which the API is attached. + It's important to note that this option is incompatible if the Ingress or IngressRoute specifies multiple backend services. + The Path must be accessible via a GET request method and should serve a YAML or JSON document containing the OpenAPI specification. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + url: + description: |- + URL is a Traefik Hub agent accessible URL for obtaining the OpenAPI specification. + The URL must be accessible via a GET request method and should serve a YAML or JSON document containing the OpenAPI specification. + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + type: object + x-kubernetes-validations: + - message: path or url must be defined + rule: has(self.path) || has(self.url) + versions: + description: Versions are the different APIVersions available. + items: + description: APIVersionRef references an APIVersion. + properties: + name: + description: Name of the APIVersion. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + minItems: 1 + type: array + type: object + status: + description: The current status of this API. + properties: + hash: + description: Hash is a hash representing the API. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/crds/hub.traefik.io_apiversions.yaml b/traefik/crds/hub.traefik.io_apiversions.yaml new file mode 100644 index 000000000..97184effe --- /dev/null +++ b/traefik/crds/hub.traefik.io_apiversions.yaml @@ -0,0 +1,194 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: apiversions.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: APIVersion + listKind: APIVersionList + plural: apiversions + singular: apiversion + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.title + name: Title + type: string + - jsonPath: .spec.release + name: Release + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: APIVersion defines a version of an API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this APIVersion. + properties: + openApiSpec: + description: OpenAPISpec defines the API contract as an OpenAPI specification. + properties: + operationSets: + description: OperationSets defines the sets of operations to be + referenced for granular filtering in APIAccesses. + items: + description: |- + OperationSet gives a name to a set of matching OpenAPI operations. + This set of operations can then be referenced for granular filtering in APIAccesses. + properties: + matchers: + description: Matchers defines a list of alternative rules + for matching OpenAPI operations. + items: + description: OperationMatcher defines criteria for matching + an OpenAPI operation. + minProperties: 1 + properties: + methods: + description: Methods specifies the HTTP methods to + be included for selection. + items: + type: string + maxItems: 10 + type: array + path: + description: Path specifies the exact path of the + operations to select. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + pathPrefix: + description: PathPrefix specifies the path prefix + of the operations to select. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + pathRegex: + description: PathRegex specifies a regular expression + pattern for matching operations based on their paths. + type: string + type: object + x-kubernetes-validations: + - message: path, pathPrefix and pathRegex are mutually + exclusive + rule: '[has(self.path), has(self.pathPrefix), has(self.pathRegex)].filter(x, + x).size() <= 1' + maxItems: 100 + minItems: 1 + type: array + name: + description: Name is the name of the OperationSet to reference + in APIAccesses. + maxLength: 253 + type: string + required: + - matchers + - name + type: object + maxItems: 100 + type: array + override: + description: Override holds data used to override OpenAPI specification. + properties: + servers: + items: + properties: + url: + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + required: + - url + type: object + maxItems: 100 + minItems: 1 + type: array + required: + - servers + type: object + path: + description: |- + Path specifies the endpoint path within the Kubernetes Service where the OpenAPI specification can be obtained. + The Service queried is determined by the associated Ingress, IngressRoute, or HTTPRoute resource to which the API is attached. + It's important to note that this option is incompatible if the Ingress or IngressRoute specifies multiple backend services. + The Path must be accessible via a GET request method and should serve a YAML or JSON document containing the OpenAPI specification. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: must start with a '/' + rule: self.startsWith('/') + - message: cannot contains '../' + rule: '!self.matches(r"""(\/\.\.\/)|(\/\.\.$)""")' + url: + description: |- + URL is a Traefik Hub agent accessible URL for obtaining the OpenAPI specification. + The URL must be accessible via a GET request method and should serve a YAML or JSON document containing the OpenAPI specification. + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + type: object + x-kubernetes-validations: + - message: path or url must be defined + rule: has(self.path) || has(self.url) + release: + description: |- + Release is the version number of the API. + This value must follow the SemVer format: https://semver.org/ + maxLength: 100 + type: string + x-kubernetes-validations: + - message: must be a valid semver version + rule: self.matches(r"""^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""") + title: + description: Title is the public facing name of the APIVersion. + type: string + required: + - release + type: object + status: + description: The current status of this APIVersion. + properties: + hash: + description: Hash is a hash representing the APIVersion. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/traefik/crds/hub.traefik.io_managedsubscriptions.yaml b/traefik/crds/hub.traefik.io_managedsubscriptions.yaml new file mode 100644 index 000000000..ca52b4f83 --- /dev/null +++ b/traefik/crds/hub.traefik.io_managedsubscriptions.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: managedsubscriptions.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: ManagedSubscription + listKind: ManagedSubscriptionList + plural: managedsubscriptions + singular: managedsubscription + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ManagedSubscription defines a Subscription managed by the API manager as the result of a pre-negotiation with its + API consumers. This subscription grant consuming access to a set of APIs to a set of Applications. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The desired behavior of this ManagedSubscription. + properties: + apiBundles: + description: |- + APIBundles defines a set of APIBundle that will be accessible. + Multiple ManagedSubscriptions can select the same APIBundles. + items: + description: APIBundleReference references an APIBundle. + properties: + name: + description: Name of the APIBundle. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apiBundles + rule: self.all(x, self.exists_one(y, x.name == y.name)) + apiPlan: + description: APIPlan defines which APIPlan will be used. + properties: + name: + description: Name of the APIPlan. + maxLength: 253 + type: string + required: + - name + type: object + apiSelector: + description: |- + APISelector selects the APIs that will be accessible. + Multiple ManagedSubscriptions can select the same set of APIs. + This field is optional and follows standard label selector semantics. + An empty APISelector matches any API. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + apis: + description: |- + APIs defines a set of APIs that will be accessible. + Multiple ManagedSubscriptions can select the same APIs. + When combined with APISelector, this set of APIs is appended to the matching APIs. + items: + description: APIReference references an API. + properties: + name: + description: Name of the API. + maxLength: 253 + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-validations: + - message: duplicated apis + rule: self.all(x, self.exists_one(y, x.name == y.name)) + applications: + description: |- + Applications references the Applications that will gain access to the specified APIs. + Multiple ManagedSubscriptions can select the same AppID. + items: + description: ApplicationReference references an Application. + properties: + appId: + description: |- + AppID is the public identifier of the application. + In the case of OIDC, it corresponds to the clientId. + maxLength: 253 + type: string + required: + - appId + type: object + maxItems: 100 + minItems: 1 + type: array + claims: + description: Claims specifies an expression that validate claims in + order to authorize the request. + type: string + operationFilter: + description: |- + OperationFilter specifies the allowed operations on APIs and APIVersions. + If not set, all operations are available. + An empty OperationFilter prohibits all operations. + properties: + include: + description: Include defines the names of OperationSets that will + be accessible. + items: + type: string + maxItems: 100 + type: array + type: object + weight: + description: |- + Weight specifies the evaluation order of the APIPlan. + When multiple ManagedSubscriptions targets the same API and Application with different APIPlan, + the APIPlan with the highest weight will be enforced. If weights are equal, alphabetical order is used. + type: integer + x-kubernetes-validations: + - message: must be a positive number + rule: self >= 0 + required: + - applications + type: object + status: + description: The current status of this ManagedSubscription. + properties: + hash: + description: Hash is a hash representing the ManagedSubscription. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true diff --git a/traefik/values.schema.json b/traefik/values.schema.json index 22878a9f5..d591b7463 100644 --- a/traefik/values.schema.json +++ b/traefik/values.schema.json @@ -1674,11 +1674,22 @@ }, "traefik-crds": { "properties": { - "gateway_api": { - "type": "string" + "enabled": { + "type": "boolean" + }, + "gatewayAPI": { + "default": false, + "type": [ + "string", + "boolean" + ] }, "hub": { - "type": "string" + "default": false, + "type": [ + "string", + "boolean" + ] }, "traefik": { "type": "boolean" diff --git a/traefik/values.yaml b/traefik/values.yaml index 510526271..48c06b1e9 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -967,9 +967,12 @@ hub: sendlogs: # @schema type:[boolean, null] traefik-crds: + # -- Set it to true to opt-in CRD management + enabled: false + # -- Set all the following to false if you want to manage CRDs your-self traefik: true - hub: | + hub: | # @schema type:[string, boolean]; default: false {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} - gateway_api: | + gatewayAPI: | # @schema type:[string, boolean]; default: false {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} From a21dae9b83242fd8d9545fa93b1d53e481f66f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Tue, 17 Dec 2024 07:53:56 +0100 Subject: [PATCH 32/44] fix: doc --- traefik/VALUES.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/traefik/VALUES.md b/traefik/VALUES.md index 41df7427e..850188553 100644 --- a/traefik/VALUES.md +++ b/traefik/VALUES.md @@ -321,15 +321,11 @@ Kubernetes: `>=1.22.0-0` | tracing.otlp.http.tls.cert | string | `""` | The path to the public certificate. When using this option, setting the key option is required. | | tracing.otlp.http.tls.insecureSkipVerify | bool | `false` | When set to true, the TLS connection accepts any certificate presented by the server regardless of the hostnames it covers. | | tracing.otlp.http.tls.key | string | `""` | The path to the private key. When using this option, setting the cert option is required. | -<<<<<<< HEAD | tracing.safeQueryParams | list | `[]` | By default, all query parameters are redacted. Defines the list of query parameters to not redact. | | tracing.sampleRate | string | `nil` | The proportion of requests to trace, specified between 0.0 and 1.0. Default: 1.0. | | tracing.serviceName | string | `nil` | Service name used in selected backend. Default: traefik. | -| traefik-crds.gateway_api | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | -======= | traefik-crds.enabled | bool | `false` | Set it to true to opt-in CRD management | | traefik-crds.gatewayAPI | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | ->>>>>>> b296543 (fix: rename gateway api + add enabled flag) | traefik-crds.hub | string | `"{{- tpl \"and .Values.hub.token .Values.hub.apimanagement.enabled\"' . }}\n"` | | | traefik-crds.traefik | bool | `true` | Set all the following to false if you want to manage CRDs your-self | | updateStrategy.rollingUpdate.maxSurge | int | `1` | | From 4da2fa066f06504889a772eea58edbb89bbe0b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 8 Jan 2025 15:47:08 +0100 Subject: [PATCH 33/44] fix: remove dependency --- Makefile | 3 --- README.md | 34 +++++++++++++++++++++---------- traefik-crds/VALUES.md | 4 +--- traefik-crds/kustomization.yaml | 28 ++++++------------------- traefik-crds/tests/crds_test.yaml | 10 ++++----- traefik-crds/values.schema.json | 10 --------- traefik-crds/values.yaml | 4 +--- traefik/Chart.yaml | 5 ----- traefik/VALUES.md | 8 -------- traefik/values.schema.json | 25 ----------------------- traefik/values.yaml | 11 ---------- 11 files changed, 35 insertions(+), 107 deletions(-) diff --git a/Makefile b/Makefile index d0dca5f9c..a6b0a16f9 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,6 @@ traefik/tests/__snapshot__: test: traefik/tests/__snapshot__ docker run ${DOCKER_ARGS} --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_HELM_UNITTEST) /charts/hack/test.sh -deps: - helm dependency update traefik - lint: docker run ${DOCKER_ARGS} --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh lint diff --git a/README.md b/README.md index 3d7293aa7..079d08b3e 100644 --- a/README.md +++ b/README.md @@ -103,26 +103,38 @@ New major version indicates that there is an incompatible breaking change. ### Upgrade to 34.X -Starting from this release, the new traefik helm CRD management which works around [Helm caveats](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations) system is enabled by default: +Starting from this release, a new chart has been published to help users managing traefik CRD. It works around [Helm caveats](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations). +This chart is comes aside main traefik chart. + +To install those two charts from scratch: ```bash # Update repository helm repo update # See current Chart & Traefik version helm search repo traefik/traefik -# Change CRDs ownership -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' -# If you use gateway API, you might also want to change Gateway API ownership -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' -# Upgrade Traefik -helm upgrade traefik traefik/traefik +# Install traefik-crds chart +helm install traefik-crds traefik/traefik-crds -n traefik --create-namespace +# Install traefik but skip crds installation +helm install traefik traefik/traefik -n traefik --create-namespace --skip-crds + +# Check that both charts are installed: +helm list -n traefik +# NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +# traefik traefik 1 2025-01-08 15:37:24.918465001 +0100 CET deployed traefik-33.2.1 v3.2.3 +# traefik-crds traefik 1 2025-01-08 15:37:18.863333527 +0100 CET deployed traefik-crds-0.0.1 ``` -If you still want to manage CRDs your self, it can be opt-out: - +To upgrade from an already installed chart: ```bash -# Upgrade Traefik and skip all CRDs installation -helm upgrade traefik traefik/traefik --set traefik-crds.enabled=true --set traefik-crds.traefik=false --set traefik-crds.hub=false --set traefik-crds.gatewayAPI=false +# Update repository +helm repo update +# Change CRDs ownership +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik-crds"}]' +# If you use gateway API, you might also want to change Gateway API ownership +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' +# Upgrade Traefik +helm install traefik-crds traefik/traefik-crds -n traefik ``` ### Upgrade up to 27.X diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index a7ddb2a3f..522718975 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -29,11 +29,9 @@ Kubernetes: `>=1.22.0-0` | Key | Type | Default | Description | |-----|------|---------|-------------| | deleteOnUninstall | bool | `false` | | -| enabled | bool | `true` | | | gatewayAPI | bool | `false` | | -| global | string | `nil` | | | hub | bool | `false` | | -| traefik | bool | `false` | | +| traefik | bool | `true` | | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/traefik-crds/kustomization.yaml b/traefik-crds/kustomization.yaml index 805135a05..fd023fef1 100644 --- a/traefik-crds/kustomization.yaml +++ b/traefik-crds/kustomization.yaml @@ -2,35 +2,19 @@ kind: Kustomization apiVersion: kustomize.config.k8s.io/v1beta1 resources: -<<<<<<< HEAD - # curl -o crds-files/gateway_api/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml - - crds-files/gateway_api/gateway-standard-install.yaml - - crds-files/hub.traefik.io_accesscontrolpolicies.yaml - - crds-files/hub.traefik.io_aiservices.yaml - - crds-files/hub.traefik.io_apiaccesses.yaml - - crds-files/hub.traefik.io_apibundles.yaml - - crds-files/hub.traefik.io_apicatalogitems.yaml - - crds-files/hub.traefik.io_apiplans.yaml - - crds-files/hub.traefik.io_apiportals.yaml - - crds-files/hub.traefik.io_apiratelimits.yaml - - crds-files/hub.traefik.io_apis.yaml - - crds-files/hub.traefik.io_apiversions.yaml - - crds-files/hub.traefik.io_managedsubscriptions.yaml -======= - # curl -o gateway-standard-install-v1.2.0.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml - - crds-files/gatewayAPI/gateway-standard-install-v1.2.0.yaml + # curl -o crds-files/gatewayAPI/gateway-standard-install.yaml -L https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml + - crds-files/gatewayAPI/gateway-standard-install.yaml - crds-files/hub/hub.traefik.io_accesscontrolpolicies.yaml - - crds-files/hub/hub.traefik.io_aiservices.yaml - crds-files/hub/hub.traefik.io_apiaccesses.yaml - - crds-files/hub/hub.traefik.io_apibundles.yaml - crds-files/hub/hub.traefik.io_apicatalogitems.yaml - - crds-files/hub/hub.traefik.io_apiplans.yaml + - crds-files/hub/hub.traefik.io_managedsubscriptions.yaml - crds-files/hub/hub.traefik.io_apiportals.yaml - crds-files/hub/hub.traefik.io_apiratelimits.yaml - crds-files/hub/hub.traefik.io_apis.yaml - crds-files/hub/hub.traefik.io_apiversions.yaml - - crds-files/hub/hub.traefik.io_managedsubscriptions.yaml ->>>>>>> b296543 (fix: rename gateway api + add enabled flag) + - crds-files/hub/hub.traefik.io_apiplans.yaml + - crds-files/hub/hub.traefik.io_apibundles.yaml + - crds-files/hub/hub.traefik.io_aiservices.yaml - crds-files/traefik/traefik.io_ingressroutes.yaml - crds-files/traefik/traefik.io_ingressroutetcps.yaml - crds-files/traefik/traefik.io_ingressrouteudps.yaml diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml index c9dbe2ec6..d77b1de1d 100644 --- a/traefik-crds/tests/crds_test.yaml +++ b/traefik-crds/tests/crds_test.yaml @@ -2,12 +2,7 @@ suite: CRDs templates: - crds.yaml tests: - - it: shouldn't have any crds by default - asserts: - - hasDocuments: - count: 0 - - - it: should have all Traefik crds + - it: should have all Traefik crds by default set: traefik: true asserts: @@ -27,6 +22,7 @@ tests: - it: should have all Traefik Hub crds set: + traefik: false hub: true asserts: - hasDocuments: @@ -45,6 +41,7 @@ tests: - it: should have all Gateway API crds set: + traefik: false gatewayAPI: true asserts: - hasDocuments: @@ -63,6 +60,7 @@ tests: - it: should have all Gateway API crds without helm keep resource policy set: + traefik: false gatewayAPI: true deleteOnUninstall: true asserts: diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index c79af9218..f176d34a5 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -7,9 +7,6 @@ "deleteOnUninstall": { "type": "boolean" }, - "enabled": { - "type": "boolean" - }, "gatewayAPI": { "default": false, "type": [ @@ -17,13 +14,6 @@ "boolean" ] }, - "global": { - "additionalProperties": true, - "type": [ - "object", - "null" - ] - }, "hub": { "default": false, "type": [ diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index 35b12a591..021de2ac4 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,6 +1,4 @@ -global: # @schema type:[object, null]; additionalProperties: true -enabled: true -traefik: false +traefik: true gatewayAPI: false # @schema type:[string, boolean]; default: false hub: false # @schema type:[string, boolean]; default: false deleteOnUninstall: false diff --git a/traefik/Chart.yaml b/traefik/Chart.yaml index 7b6f5cce6..03b8992cc 100644 --- a/traefik/Chart.yaml +++ b/traefik/Chart.yaml @@ -27,8 +27,3 @@ annotations: artifacthub.io/changes: | - "fix(Gateway API): CRDs should only be defined once" - "chore(release): 🚀 publish v33.2.1" -dependencies: - - name: traefik-crds - version: 0.0.1 - repository: https://traefik.github.io/charts - condition: traefik-crds.enabled diff --git a/traefik/VALUES.md b/traefik/VALUES.md index f06269be6..5a6b595f3 100644 --- a/traefik/VALUES.md +++ b/traefik/VALUES.md @@ -24,10 +24,6 @@ A Traefik based Kubernetes ingress controller Kubernetes: `>=1.22.0-0` -| Repository | Name | Version | -|------------|------|---------| -| https://traefik.github.io/charts | traefik-crds | 0.0.1 | - ## Values | Key | Type | Default | Description | @@ -324,10 +320,6 @@ Kubernetes: `>=1.22.0-0` | tracing.safeQueryParams | list | `[]` | By default, all query parameters are redacted. Defines the list of query parameters to not redact. | | tracing.sampleRate | string | `nil` | The proportion of requests to trace, specified between 0.0 and 1.0. Default: 1.0. | | tracing.serviceName | string | `nil` | Service name used in selected backend. Default: traefik. | -| traefik-crds.enabled | bool | `false` | Set it to true to opt-in CRD management | -| traefik-crds.gatewayAPI | string | `"{{- tpl \".Values.providers.kubernetesGateway.enabled\" . }}\n"` | | -| traefik-crds.hub | string | `"{{- tpl \"and .Values.hub.token .Values.hub.apimanagement.enabled\"' . }}\n"` | | -| traefik-crds.traefik | bool | `true` | Set all the following to false if you want to manage CRDs your-self | | updateStrategy.rollingUpdate.maxSurge | int | `1` | | | updateStrategy.rollingUpdate.maxUnavailable | int | `0` | | | updateStrategy.type | string | `"RollingUpdate"` | Customize updateStrategy of Deployment or DaemonSet | diff --git a/traefik/values.schema.json b/traefik/values.schema.json index d591b7463..aa76667a7 100644 --- a/traefik/values.schema.json +++ b/traefik/values.schema.json @@ -1672,31 +1672,6 @@ }, "type": "object" }, - "traefik-crds": { - "properties": { - "enabled": { - "type": "boolean" - }, - "gatewayAPI": { - "default": false, - "type": [ - "string", - "boolean" - ] - }, - "hub": { - "default": false, - "type": [ - "string", - "boolean" - ] - }, - "traefik": { - "type": "boolean" - } - }, - "type": "object" - }, "updateStrategy": { "additionalProperties": false, "properties": { diff --git a/traefik/values.yaml b/traefik/values.yaml index 48c06b1e9..78c8ea4f4 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -965,14 +965,3 @@ hub: insecureSkipVerify: false # Enable export of errors logs to the platform. Default: true. sendlogs: # @schema type:[boolean, null] - -traefik-crds: - # -- Set it to true to opt-in CRD management - enabled: false - - # -- Set all the following to false if you want to manage CRDs your-self - traefik: true - hub: | # @schema type:[string, boolean]; default: false - {{- tpl "and .Values.hub.token .Values.hub.apimanagement.enabled"' . }} - gatewayAPI: | # @schema type:[string, boolean]; default: false - {{- tpl ".Values.providers.kubernetesGateway.enabled" . }} From 92157e4c71642c6fe5283237c6453e3690638bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 8 Jan 2025 15:56:13 +0100 Subject: [PATCH 34/44] fix: doc --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 079d08b3e..9f968f9ab 100644 --- a/README.md +++ b/README.md @@ -88,17 +88,12 @@ One can check what has changed in the [Changelog](./traefik/Changelog.md). helm repo update # See current Chart & Traefik version helm search repo traefik/traefik +# Update CRDs (Traefik Proxy v3 CRDs) +kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik/crds/ # Upgrade Traefik helm upgrade traefik traefik/traefik ``` -If you opt-out CRDs management system, you can still apply it manually: - -```bash -# Update CRDs (Traefik Proxy v3 CRDs) -kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik-crds/ -``` - New major version indicates that there is an incompatible breaking change. ### Upgrade to 34.X From 909a27790551a4b1d669ae006fe7580d7eb28268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Wed, 8 Jan 2025 16:00:59 +0100 Subject: [PATCH 35/44] fix: version --- README.md | 2 +- traefik-crds/Chart.yaml | 2 +- traefik-crds/VALUES.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9f968f9ab..f413e9801 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ helm install traefik traefik/traefik -n traefik --create-namespace --skip-crds helm list -n traefik # NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION # traefik traefik 1 2025-01-08 15:37:24.918465001 +0100 CET deployed traefik-33.2.1 v3.2.3 -# traefik-crds traefik 1 2025-01-08 15:37:18.863333527 +0100 CET deployed traefik-crds-0.0.1 +# traefik-crds traefik 1 2025-01-08 15:37:18.863333527 +0100 CET deployed traefik-crds-1.0.0 ``` To upgrade from an already installed chart: diff --git a/traefik-crds/Chart.yaml b/traefik-crds/Chart.yaml index 1119f044d..f14f60a92 100644 --- a/traefik-crds/Chart.yaml +++ b/traefik-crds/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: traefik-crds description: A Traefik based Kubernetes ingress controller type: application -version: 0.0.1 +version: 1.0.0 kubeVersion: ">=1.22.0-0" keywords: - traefik diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index 522718975..a8af264db 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -1,6 +1,6 @@ # traefik-crds -![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Traefik based Kubernetes ingress controller From 694cfd54ae8f4476c4adf4d4980a535f4ba07aca Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Wed, 8 Jan 2025 16:38:04 +0100 Subject: [PATCH 36/44] README review --- README.md | 57 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f413e9801..31e66f4c6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ This chart support policy is aligned with [upstream support policy](https://doc. See [Migration guide from v2 to v3](https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/) and upgrading section of this chart on CRDs. +Starting with v34.x, to work around [Helm caveats](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations), it's possible to use an additional Chart dedicated to CRDs: **traefik-crds**. + ### Philosophy The Traefik HelmChart is focused on Traefik deployment configuration. @@ -56,7 +58,9 @@ Due to changes in API Group of Traefik CRDs from `containo.us` to `traefik.io`, | Chart v23.0.0 and above | [x] | [x] | | Chart v28.0.0 and above | | [x] | -### Deploying Traefik +### Deploying + +#### With Traefik chart ```bash helm install traefik traefik/traefik @@ -75,13 +79,34 @@ Complete documentation on all available parameters is in the [default file](./tr helm install -f myvalues.yaml traefik traefik/traefik ``` -🛂 **Warning**: Helm v2 support was removed in the chart version 10.0.0. +:warning: If you want to use CRDs chart and Traefik chart is already deployed, +you **have** to change ownership on CRDs **before** installating CRDs chart: + +```bash +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik-crds"}]' +# If you use gateway API, you might also want to change Gateway API ownership +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' +helm install traefik-crds traefik/traefik-crds +``` + +#### With Traefik & CRDs chart + +```bash +helm install traefik-crds traefik/traefik-crds +helm install traefik traefik/traefik --skip-crds +helm list # should display two charts installed +``` ## Upgrading One can check what has changed in the [Changelog](./traefik/Changelog.md). -:warning: Please read carefully release notes of this chart before upgrading CRDs. +:warning: Please read carefully release notes of this chart before upgrading. + +### With Traefik chart + +When using Helm native management for CRDs, user **MUST** upgrade CRDs before calling _helm upgrade_ command. +CRDs are **not** updated by Helm. See [HIP-0011](https://github.com/helm/community/blob/main/hips/hip-0011.md) for details. ```bash # Update repository @@ -96,28 +121,17 @@ helm upgrade traefik traefik/traefik New major version indicates that there is an incompatible breaking change. -### Upgrade to 34.X - -Starting from this release, a new chart has been published to help users managing traefik CRD. It works around [Helm caveats](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations). -This chart is comes aside main traefik chart. - -To install those two charts from scratch: +### With Traefik & CRDs charts ```bash # Update repository helm repo update # See current Chart & Traefik version helm search repo traefik/traefik -# Install traefik-crds chart -helm install traefik-crds traefik/traefik-crds -n traefik --create-namespace -# Install traefik but skip crds installation -helm install traefik traefik/traefik -n traefik --create-namespace --skip-crds - -# Check that both charts are installed: -helm list -n traefik -# NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -# traefik traefik 1 2025-01-08 15:37:24.918465001 +0100 CET deployed traefik-33.2.1 v3.2.3 -# traefik-crds traefik 1 2025-01-08 15:37:18.863333527 +0100 CET deployed traefik-crds-1.0.0 +# Update CRDs (Traefik Proxy v3 CRDs) +helm upgrade traefik-crds traefik/traefik +# Upgrade Traefik +helm upgrade traefik traefik/traefik ``` To upgrade from an already installed chart: @@ -125,11 +139,8 @@ To upgrade from an already installed chart: # Update repository helm repo update # Change CRDs ownership -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik-crds"}]' -# If you use gateway API, you might also want to change Gateway API ownership -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' # Upgrade Traefik -helm install traefik-crds traefik/traefik-crds -n traefik +helm install traefik-crds traefik/traefik-crds -n traefik ``` ### Upgrade up to 27.X From 4640d14eca42465d4468787c6a2a02a4da3e7a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 08:43:45 +0100 Subject: [PATCH 37/44] fix: doc --- README.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 31e66f4c6..51ae49fd3 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Due to changes in API Group of Traefik CRDs from `containo.us` to `traefik.io`, ### Deploying -#### With Traefik chart +#### The standard way ```bash helm install traefik traefik/traefik @@ -79,17 +79,7 @@ Complete documentation on all available parameters is in the [default file](./tr helm install -f myvalues.yaml traefik traefik/traefik ``` -:warning: If you want to use CRDs chart and Traefik chart is already deployed, -you **have** to change ownership on CRDs **before** installating CRDs chart: - -```bash -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik-crds"}]' -# If you use gateway API, you might also want to change Gateway API ownership -kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' -helm install traefik-crds traefik/traefik-crds -``` - -#### With Traefik & CRDs chart +#### With additional CRDs chart ```bash helm install traefik-crds traefik/traefik-crds @@ -101,9 +91,10 @@ helm list # should display two charts installed One can check what has changed in the [Changelog](./traefik/Changelog.md). -:warning: Please read carefully release notes of this chart before upgrading. +> [!WARNING] +> Please read carefully release notes of this chart before upgrading. -### With Traefik chart +### A standard installation When using Helm native management for CRDs, user **MUST** upgrade CRDs before calling _helm upgrade_ command. CRDs are **not** updated by Helm. See [HIP-0011](https://github.com/helm/community/blob/main/hips/hip-0011.md) for details. @@ -119,9 +110,20 @@ kubectl apply --server-side --force-conflicts -k https://github.com/traefik/trae helm upgrade traefik traefik/traefik ``` +> [!WARNING] +> If you want to upgrade from a standard installation to a CRDs chart powered one, +> you **have** to change ownership on CRDs **before** installing CRDs chart + +```bash +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik-crds"}]' +# If you use gateway API, you might also want to change Gateway API ownership +kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gateway.networking.k8s.io | xargs kubectl patch --type='json' -p='[{"op": "add", "path": "/metadata/labels", "value": {"app.kubernetes.io/managed-by":"Helm"}},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value":"traefik-crds"},{"op": "add", "path": "/metadata/annotations/meta.helm.sh~1release-namespace", "value":"traefik"}]' +helm install traefik-crds traefik/traefik-crds +``` + New major version indicates that there is an incompatible breaking change. -### With Traefik & CRDs charts +### A CRDs chart powered installation ```bash # Update repository From 069050adf269b884f826d95f8a3c3ddc3b96da68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 09:16:30 +0100 Subject: [PATCH 38/44] fix: CI --- .github/workflows/test.yml | 7 ++++++- Makefile | 5 ++--- hack/ct.sh | 18 ++++++++++++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5bbc99064..8f371004d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -86,7 +86,12 @@ jobs: kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=90s kubectl apply -f hack/metallb-config.yaml - - name: Check install on Kind + - name: Check install on Kind (standard) if: steps.check.outputs.release run: | make test-install + + - name: Check install on Kind (with CRDS) + if: steps.check.outputs.release + run: | + make test-install-with-crds diff --git a/Makefile b/Makefile index a6b0a16f9..8930442f7 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,8 @@ lint: docs: docker run --rm -v "$(CURDIR):/helm-docs" $(IMAGE_HELM_DOCS) -o VALUES.md -test-install: - docker run ${DOCKER_ARGS} --network=host --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -v $(HOME)/.kube:/root/.kube -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh install - +test-%: + docker run ${DOCKER_ARGS} --network=host --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -v $(HOME)/.kube:/root/.kube -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh $* # Requires to install schema generation plugin beforehand # $ helm plugin install https://github.com/losisin/helm-values-schema-json.git diff --git a/hack/ct.sh b/hack/ct.sh index 06f7f69e2..4d186304a 100644 --- a/hack/ct.sh +++ b/hack/ct.sh @@ -1,6 +1,20 @@ #!/bin/bash +ACTION=$1 + git config --global --add safe.directory /charts -ct $1 --config=.github/chart-testing.yaml --charts traefik/ -ct $1 --config=.github/chart-testing.yaml --charts traefik-crds/ +case "${ACTION}" in +install-with-crds) + ACTION="install" + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik-crds/ + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ --helm-extra-args '--skip-crds' + ;; +install) + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ + ;; +*) + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik-crds/ + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ + ;; +esac From de095f09e3c5fe8364188fc6070e084266fdfa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 09:25:13 +0100 Subject: [PATCH 39/44] fix: apply suggestions from @mloiseleur's code review Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 51ae49fd3..c6e8c5c8b 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ helm upgrade traefik traefik/traefik ``` > [!WARNING] -> If you want to upgrade from a standard installation to a CRDs chart powered one, +> When upgrading from standard installation to the one with additional CRDs chart, > you **have** to change ownership on CRDs **before** installing CRDs chart ```bash @@ -123,7 +123,7 @@ helm install traefik-crds traefik/traefik-crds New major version indicates that there is an incompatible breaking change. -### A CRDs chart powered installation +### An installation with additional CRDs chart ```bash # Update repository @@ -136,15 +136,6 @@ helm upgrade traefik-crds traefik/traefik helm upgrade traefik traefik/traefik ``` -To upgrade from an already installed chart: -```bash -# Update repository -helm repo update -# Change CRDs ownership -# Upgrade Traefik -helm install traefik-crds traefik/traefik-crds -n traefik -``` - ### Upgrade up to 27.X When upgrading on Traefik Proxy v2 version, one need to stay at Traefik Helm Chart v27.x. The command to upgrade to the latest Traefik Proxy v2 CRD is: From b6bc446c8d105a7920d021ace5b9a9190cc96287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 09:31:04 +0100 Subject: [PATCH 40/44] fix: CI --- hack/ct.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hack/ct.sh b/hack/ct.sh index 4d186304a..8ca135442 100644 --- a/hack/ct.sh +++ b/hack/ct.sh @@ -7,8 +7,9 @@ git config --global --add safe.directory /charts case "${ACTION}" in install-with-crds) ACTION="install" - ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik-crds/ - ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ --helm-extra-args '--skip-crds' + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik-crds/ --skip-clean-up + # # --skip-clean-up is here because helm uninstall doesn't have a --skip-crds flag ... + ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ --helm-extra-args '--skip-crds' --skip-clean-up ;; install) ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ From fdbf4b6102198dbad411e7a6b17140b65479a358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 09:57:29 +0100 Subject: [PATCH 41/44] fix: apply suggestions from @mloiseleur's code review Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- README.md | 2 +- traefik-crds/values.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c6e8c5c8b..d06b10556 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ helm list # should display two charts installed One can check what has changed in the [Changelog](./traefik/Changelog.md). +New major version indicates that there is an incompatible breaking change. > [!WARNING] > Please read carefully release notes of this chart before upgrading. @@ -121,7 +122,6 @@ kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep gatewa helm install traefik-crds traefik/traefik-crds ``` -New major version indicates that there is an incompatible breaking change. ### An installation with additional CRDs chart diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index 021de2ac4..ddeae5903 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,4 +1,4 @@ traefik: true -gatewayAPI: false # @schema type:[string, boolean]; default: false -hub: false # @schema type:[string, boolean]; default: false +gatewayAPI: false +hub: false deleteOnUninstall: false From b99068e39994d0e68dac585b301ce36590531d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 10:22:22 +0100 Subject: [PATCH 42/44] fix: CI --- hack/ct.sh | 9 ++++++--- traefik-crds/values.schema.json | 12 ++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/hack/ct.sh b/hack/ct.sh index 8ca135442..d9ce0fadc 100644 --- a/hack/ct.sh +++ b/hack/ct.sh @@ -7,11 +7,14 @@ git config --global --add safe.directory /charts case "${ACTION}" in install-with-crds) ACTION="install" - ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik-crds/ --skip-clean-up - # # --skip-clean-up is here because helm uninstall doesn't have a --skip-crds flag ... - ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ --helm-extra-args '--skip-crds' --skip-clean-up + + # deleting existing CRDs + kubectl get customresourcedefinitions.apiextensions.k8s.io -o name | grep traefik.io | xargs kubectl delete crd + ct "${ACTION}" --namespace traefik --config=.github/chart-testing.yaml --charts traefik-crds/ + ct "${ACTION}" --namespace traefik --config=.github/chart-testing.yaml --charts traefik/ ;; install) + kubectl create namespace traefik ct "${ACTION}" --config=.github/chart-testing.yaml --charts traefik/ ;; *) diff --git a/traefik-crds/values.schema.json b/traefik-crds/values.schema.json index f176d34a5..91f5e2d3b 100644 --- a/traefik-crds/values.schema.json +++ b/traefik-crds/values.schema.json @@ -8,18 +8,10 @@ "type": "boolean" }, "gatewayAPI": { - "default": false, - "type": [ - "string", - "boolean" - ] + "type": "boolean" }, "hub": { - "default": false, - "type": [ - "string", - "boolean" - ] + "type": "boolean" }, "traefik": { "type": "boolean" From d686dd2462ad5f5fd501bf6981db06d3af03ee6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Fri, 10 Jan 2025 10:35:29 +0100 Subject: [PATCH 43/44] fix: doc --- traefik-crds/VALUES.md | 8 ++++---- traefik-crds/values.yaml | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/traefik-crds/VALUES.md b/traefik-crds/VALUES.md index a8af264db..a6d263b83 100644 --- a/traefik-crds/VALUES.md +++ b/traefik-crds/VALUES.md @@ -28,10 +28,10 @@ Kubernetes: `>=1.22.0-0` | Key | Type | Default | Description | |-----|------|---------|-------------| -| deleteOnUninstall | bool | `false` | | -| gatewayAPI | bool | `false` | | -| hub | bool | `false` | | -| traefik | bool | `true` | | +| deleteOnUninstall | bool | `false` | Set it to true if you want to uninstall CRDs when uninstalling this chart. By default, CRDs will be kept so your custom resources will not be deleted accidentally. | +| gatewayAPI | bool | `false` | Set it to true to install GatewayAPI CRDs. Needed if you set providers.kubernetesGateway.enabled to true in main chart | +| hub | bool | `false` | Set it to true to install Traefik Hub CRDs. Needed if you set hub.enabled to true in main chart | +| traefik | bool | `true` | Install Traefik CRDs by default | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/traefik-crds/values.yaml b/traefik-crds/values.yaml index ddeae5903..6aca6cbbf 100644 --- a/traefik-crds/values.yaml +++ b/traefik-crds/values.yaml @@ -1,4 +1,15 @@ +# Default values for Traefik CRDs +# This is a YAML-formatted file. +# Declare variables to be passed into templates + +# -- Install Traefik CRDs by default traefik: true -gatewayAPI: false -hub: false +# -- Set it to true to install GatewayAPI CRDs. +# Needed if you set providers.kubernetesGateway.enabled to true in main chart +gatewayAPI: false +# -- Set it to true to install Traefik Hub CRDs. +# Needed if you set hub.enabled to true in main chart +hub: false +# -- Set it to true if you want to uninstall CRDs when uninstalling this chart. +# By default, CRDs will be kept so your custom resources will not be deleted accidentally. deleteOnUninstall: false From afa08e7343e9cefad4f6022c6d19ef0b2191aecd Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Fri, 10 Jan 2025 11:05:26 +0100 Subject: [PATCH 44/44] add linter on crds consistency --- .github/workflows/test.yml | 3 +++ Makefile | 3 +++ hack/check-crds-consistency.sh | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100755 hack/check-crds-consistency.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a564cdabc..18ae104e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,6 +54,9 @@ jobs: - name: Test overrideNamespace run: make test-ns + - name: Test CRDs consistency + run: make test-crds-consistency + - name: Test if it's a release PR id: check run: | diff --git a/Makefile b/Makefile index 4b64a034f..6e55ddfe7 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,9 @@ test: traefik/tests/__snapshot__ test-ns: ./hack/check-ns.sh +test-crds-consistency: + ./hack/check-crds-consistency.sh + lint: docker run ${DOCKER_ARGS} --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh lint diff --git a/hack/check-crds-consistency.sh b/hack/check-crds-consistency.sh new file mode 100755 index 000000000..4ddb154e1 --- /dev/null +++ b/hack/check-crds-consistency.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +nativecrd=$(mktemp) +chartcrd=$(mktemp) + +kustomize build traefik/crds > "${nativecrd}" +kustomize build traefik-crds/ > "${chartcrd}" + +diff -Naur "${nativecrd}" "${chartcrd}" > /dev/null 2>&1 +exitcode=$? +rm -f "${nativecrd}" "${chartcrd}" + +if [ $exitcode -ne 0 ] ; then + echo "⚠️ CRDs are inconsistent between traefik/crds and traefik-crds/ !" + exit 1 +fi + +echo "✅ CRDs are consistent." +exit 0